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

  1. Set TokenLocality to exactly "local" or "global" (lowercase).
  2. Use the exported constants structs.ACLAuthMethodTokenLocalityLocal / ...Global in Go code instead of string literals.
  3. 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

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.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/a7503cea8b50c97a. Report an issue: GitHub.