{"record":{"id":"0425f60de783c9ed","repo":"hashicorp/nomad","slug":"service-identity-must-provide-at-least-one-target","errorCode":null,"errorMessage":"Service identity must provide at least one target aud value","messagePattern":"Service identity must provide at least one target aud value","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/services.go","lineNumber":936,"sourceCode":"\t\t\tmErr.Errors = append(mErr.Errors, err)\n\t\t}\n\t}\n\n\t// Services using the Nomad provider do not support Consul connect.\n\tif s.Connect != nil {\n\t\tmErr.Errors = append(mErr.Errors, errors.New(\"Service with provider nomad cannot include Connect blocks\"))\n\t}\n}\n\n// validateIdentity performs validation on workload identity field populated by\n// the job mutating hook\nfunc (s *Service) validateIdentity() error {\n\tif s.Identity == nil {\n\t\treturn nil\n\t}\n\n\tif len(s.Identity.Audience) == 0 {\n\t\treturn fmt.Errorf(\"Service identity must provide at least one target aud value\")\n\t}\n\n\treturn nil\n}\n\n// ValidateName checks if the service Name is valid and should be called after\n// the name has been interpolated\nfunc (s *Service) ValidateName(name string) error {\n\t// Ensure the service name is valid per RFC-952 §1\n\t// (https://tools.ietf.org/html/rfc952), RFC-1123 §2.1\n\t// (https://tools.ietf.org/html/rfc1123), and RFC-2782\n\t// (https://tools.ietf.org/html/rfc2782).\n\t//  This validation is enforced on Nomad, but not on Consul, however if\n\t//  consul-template is being used, service names with dots in them wont be\n\t//  admissible.\n\tre := regexp.MustCompile(`^(?i:[a-z0-9]|[a-z0-9][a-z0-9\\-]{0,61}[a-z0-9])$`)\n\tif !re.MatchString(name) {\n\t\treturn 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\")","sourceCodeStart":918,"sourceCodeEnd":954,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/services.go#L918-L954","documentation":"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.","triggerScenarios":"A service stanza with `identity { name = \"...\" }` but no `aud = [...]` array.","commonSituations":"Omitting the aud array when configuring Consul workload identities; templating the identity block where the audience list variable is empty.","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."],"exampleFix":"// before\nservice {\n  name = \"web\"\n  identity {\n    name = \"web_identity\"\n  }\n}\n// after\nservice {\n  name = \"web\"\n  identity {\n    name = \"web_identity\"\n    aud = [\"consul.io\"]\n  }\n}","handlingStrategy":"validation","validationCode":"if id := svc.Identity; id != nil && len(id.Audience) == 0 {\n  return fmt.Errorf(\"identity %q must declare at least one aud\", id.Name)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["nomad","workload-identity","jwt","validation"],"backgroundTag":"jwt-audience-missing","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}