hashicorp/nomad · error

invalid config: %w

Error message

invalid config: %w

What it means

ACLAuthMethod.Validate() wraps an error returned by a.Config.Validate(a.Type) with "invalid config: %w". The auth method's provider-specific Config (OIDC/JWT settings) failed its own validation, e.g. missing required URLs or client settings for the declared Type.

Source

Thrown at nomad/structs/acl.go:1444

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()
}

// Sanitize returns a copy of the ACLAuthMethod with any secrets redacted
func (a *ACLAuthMethod) Sanitize() *ACLAuthMethod {
	if a == nil || a.Config == nil {
		return a
	}
	// copy to ensure we do not mutate a pointer pulled directly out of state.
	clean := a.Copy()

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Read the wrapped inner error (use %w/errors.Unwrap) and supply the named field, e.g. set OIDCDiscoveryURL and OIDCClientID.
  2. If a client assertion is used, fix the fields its Validate() reports.
  3. Match the config shape to the Type: OIDC needs discovery URL + client ID; JWT needs discovery URL OR JWKS URL OR public keys.
  4. Verify the provider's discovery URL is reachable and correct (https, correct realm/tenant).

Example fix

// before
am := &structs.ACLAuthMethod{Name: "okta", Type: "OIDC", Config: &structs.ACLAuthMethodConfig{}}
// after
am := &structs.ACLAuthMethod{Name: "okta", Type: "OIDC", Config: &structs.ACLAuthMethodConfig{
  OIDCDiscoveryURL: "https://idp.example.com/.well-known/openid-configuration",
  OIDCClientID:     "nomad-client",
  BoundAudiences:   []string{"nomad-client"},
}}
Defensive patterns

Strategy: validation

Validate before calling

switch am.Type {
case "OIDC":
	if am.Config == nil || am.Config.OIDCDiscoveryURL == "" || am.Config.OIDCClientID == "" {
		return errors.New("OIDC requires Config.OIDCDiscoveryURL and Config.OIDCClientID")
	}
case "JWT":
	c := am.Config
	if c == nil || (c.OIDCDiscoveryURL == "" && c.JWKSURL == "" && len(c.JWTValidationPubKeys) == 0) {
		return errors.New("JWT requires OIDCDiscoveryURL, JWKSURL, or JWTValidationPubKeys")
	}
}

Type guard

func hasJWTSource(c *structs.ACLAuthMethodConfig) bool {
	return c != nil && (c.OIDCDiscoveryURL != "" || c.JWKSURL != "" || len(c.JWTValidationPubKeys) > 0)
}

Try / catch

if err := am.Validate(minTTL, maxTTL); err != nil {
	var inner error = errors.Unwrap(err) // walk multierror for 'invalid config:' wraps
	return fmt.Errorf("fix auth-method config: %w", err)
}

Prevention

When it happens

Trigger: For Type=OIDC: OIDCClientAssertion.Validate() failing or missing OIDCDiscoveryURL/OIDCClientID. For Type=JWT: no OIDCDiscoveryURL, no JWKSURL, and no JWTValidationPubKeys at all. The wrapped inner error names the exact missing/invalid field.

Common situations: Configuring OIDC but forgetting OIDCClientID or Discovery URL; deleting public keys/JWKS config when rotating secrets; copy-pasting a JWT config into an OIDC method or vice versa.

Related errors


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