hashicorp/nomad · error
invalid token locality '%s'
Error message
invalid token locality '%s'
What it means
ACLAuthMethod.Validate() rejects TokenLocality because it is not one of 'local' (ACLAuthMethodTokenLocalityLocal) or 'global' (ACLAuthMethodTokenLocalityGlobal). This controls whether tokens issued via the method work only on the local cluster or across federated clusters.
Source
Thrown at nomad/structs/acl.go:1435
a.TokenNameFormat = helper.Merge(a.TokenNameFormat, b.TokenNameFormat)
a.MaxTokenTTL = helper.Merge(a.MaxTokenTTL, b.MaxTokenTTL)
a.Config = helper.Merge(a.Config, b.Config)
}
}
// Validate returns an error is the ACLAuthMethod is invalid.
//
// TODO revisit possible other validity conditions in the future
func (a *ACLAuthMethod) Validate(minTTL, maxTTL time.Duration) error {
var mErr multierror.Error
if !ValidACLAuthMethod.MatchString(a.Name) {
mErr.Errors = append(mErr.Errors, fmt.Errorf("invalid name '%s'", a.Name))
}
if !slices.Contains([]string{ACLAuthMethodTokenLocalityLocal, ACLAuthMethodTokenLocalityGlobal}, a.TokenLocality) {
mErr.Errors = append(
mErr.Errors, fmt.Errorf("invalid token locality '%s'", a.TokenLocality))
}
if !slices.Contains(ValidACLAuthMethodTypes, a.Type) {
mErr.Errors = append(
mErr.Errors, fmt.Errorf("invalid token type '%s'", a.Type))
}
if err := a.Config.Validate(a.Type); err != nil {
mErr.Errors = append(mErr.Errors, fmt.Errorf("invalid config: %w", err))
}
if minTTL > a.MaxTokenTTL || a.MaxTokenTTL > maxTTL {
mErr.Errors = append(mErr.Errors, fmt.Errorf(
"invalid MaxTokenTTL value '%s' (should be between %s and %s)",
a.MaxTokenTTL.String(), minTTL.String(), maxTTL.String()))
}
return mErr.ErrorOrNil()View on GitHub (pinned to 482b49bf1a)
Solutions
- Set TokenLocality to exactly "local" or "global" (lowercase).
- Use the exported constants structs.ACLAuthMethodTokenLocalityLocal / ...Global in Go code instead of string literals.
- If the field is absent in JSON, set it explicitly in the payload.
Example fix
// before
am := &structs.ACLAuthMethod{Name: "okta", Type: "OIDC", TokenLocality: "Local"}
// after
am := &structs.ACLAuthMethod{Name: "okta", Type: "OIDC", TokenLocality: structs.ACLAuthMethodTokenLocalityLocal} Defensive patterns
Strategy: validation
Validate before calling
if am.TokenLocality != "local" && am.TokenLocality != "global" {
return fmt.Errorf("TokenLocality must be local|global, got %q", am.TokenLocality)
} Type guard
func validTokenLocality(v string) bool { return v == "local" || v == "global" } Try / catch
if err := am.Validate(minTTL, maxTTL); err != nil {
if strings.Contains(err.Error(), "invalid token locality") {
am.TokenLocality = "local" // safe default, revalidate
}
return err
} Prevention
- Use structs.ACLAuthMethodTokenLocalityLocal/Global constants, never literals
- Locality is lowercase — watch for 'Local'/'GLOBAL' from YAML configs
- Set the field explicitly in every JSON payload
When it happens
Trigger: Upserting an ACL auth method with TokenLocality set to any string other than exactly "local" or "global", including "" (empty), "Local", or "cluster".
Common situations: Case-sensitivity mistakes ('Local'); copying config from Consul which uses different locality vocabulary; forgetting the field in hand-written JSON payloads.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- token name too long
- client token missing policies or roles
- management token cannot be associated with policies or roles
- token type must be client or management
- expiration time cannot be before create time
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/a7503cea8b50c97a.
Report an issue: GitHub.