hashicorp/nomad · error
Service identity must provide at least one target aud value
Error message
Service identity must provide at least one target aud value
What it means
validateIdentity requires that a service's identity block (workload identity for Consul / Vault JWT audience) lists at least one audience value. The identity is used to mint a JWT with `aud` claims; an empty audience list produces a useless token, so validation rejects it.
Solutions
- Add `aud = ["consul.io"]` (or the intended audiences) inside the identity block.
- Remove the identity block entirely if workload identity is not needed.
- Check templating/HCL merging so the aud list is not dropped by variable expansion.
Example fix
// before
service {
name = "web"
identity {
name = "web_identity"
}
}
// after
service {
name = "web"
identity {
name = "web_identity"
aud = ["consul.io"]
}
} Defensive patterns
Strategy: validation
Validate before calling
if id := svc.Identity; id != nil && len(id.Audience) == 0 {
return fmt.Errorf("identity %q must declare at least one aud", id.Name)
} Prevention
- Always include `aud = ["consul.io"]` (or target audiences) in identity blocks
- Check templating so aud lists are not dropped during variable expansion
- Keep identity definitions in shared snippets that include audiences
When it happens
Trigger: A service stanza with `identity { name = "..." }` but no `aud = [...]` array.
Common situations: Omitting the aud array when configuring Consul workload identities; templating the identity block where the audience list variable is empty.
Related errors
- an empty string is an invalid audience
- allocation does not exist
- can only use change_signal=
- change_signal must be specified when using change_mode=
- Duplicate default identities found
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/0425f60de783c9ed.
Report an issue: GitHub.
Appendix: source
Thrown at nomad/structs/services.go:936
mErr.Errors = append(mErr.Errors, err)
}
}
// Services using the Nomad provider do not support Consul connect.
if s.Connect != nil {
mErr.Errors = append(mErr.Errors, errors.New("Service with provider nomad cannot include Connect blocks"))
}
}
// validateIdentity performs validation on workload identity field populated by
// the job mutating hook
func (s *Service) validateIdentity() error {
if s.Identity == nil {
return nil
}
if len(s.Identity.Audience) == 0 {
return fmt.Errorf("Service identity must provide at least one target aud value")
}
return nil
}
// ValidateName checks if the service Name is valid and should be called after
// the name has been interpolated
func (s *Service) ValidateName(name string) error {
// Ensure the service name is valid per RFC-952 §1
// (https://tools.ietf.org/html/rfc952), RFC-1123 §2.1
// (https://tools.ietf.org/html/rfc1123), and RFC-2782
// (https://tools.ietf.org/html/rfc2782).
// This validation is enforced on Nomad, but not on Consul, however if
// consul-template is being used, service names with dots in them wont be
// admissible.
re := regexp.MustCompile(`^(?i:[a-z0-9]|[a-z0-9][a-z0-9\-]{0,61}[a-z0-9])$`)
if !re.MatchString(name) {
return fmt.Errorf("Service name must be valid per RFC 1123 and can contain only alphanumeric characters or dashes and must be no longer than 63 characters")View on GitHub (pinned to 482b49bf1a)