hashicorp/nomad · error

client_introduction.max_identity_ttl must be greater than de

Error message

client_introduction.max_identity_ttl must be greater than default_identity_ttl

What it means

The final client_introduction consistency check enforces `max_identity_ttl >= default_identity_ttl`. A default lifetime exceeding the advertised maximum would let the agent issue identities that immediately violate its own ceiling, so Validate() rejects the configuration outright.

Source

Thrown at command/agent/config.go:1275

		return nil
	}

	if c.Enforcement == "" {
		return errors.New("client_introduction.enforcement must be set")
	}
	if !slices.Contains(ClientIntroductionEnforcementValues, c.Enforcement) {
		return fmt.Errorf("client_introduction.enforcement must be one of %v",
			ClientIntroductionEnforcementValues)
	}

	if c.DefaultIdentityTTL < 1 {
		return errors.New("client_introduction.default_identity_ttl must be greater one")
	}
	if c.MaxIdentityTTL < 1 {
		return errors.New("client_introduction.max_identity_ttl must be greater one")
	}
	if c.MaxIdentityTTL < c.DefaultIdentityTTL {
		return errors.New("client_introduction.max_identity_ttl must be greater than default_identity_ttl")
	}

	return nil
}

// ServerJoin is used in both clients and servers to bootstrap connections to
// servers
type ServerJoin struct {
	// StartJoin is a list of addresses to attempt to join when the
	// agent starts. If Serf is unable to communicate with any of these
	// addresses, then the agent will error and exit.
	StartJoin []string `hcl:"start_join"`

	// RetryJoin is a list of addresses to join with retry enabled, or a single
	// value to find multiple servers using go-discover syntax.
	RetryJoin []string `hcl:"retry_join"`

	// RetryMaxAttempts specifies the maximum number of times to retry joining a

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Raise `max_identity_ttl` to at least the value of `default_identity_ttl`.
  2. Or lower `default_identity_ttl` so it is <= `max_identity_ttl`.
  3. Add a config linter/CI check asserting max >= default for all TTL pairs.

Example fix

// before
client_introduction {
  default_identity_ttl = "24h"
  max_identity_ttl     = "1h"
}

// after
client_introduction {
  default_identity_ttl = "1h"
  max_identity_ttl     = "24h"
}
Defensive patterns

Strategy: validation

Validate before calling

if c := cfg.ClientIntroduction; c != nil && c.MaxIdentityTTL < c.DefaultIdentityTTL {
    return errors.New("client_introduction.max_identity_ttl must be >= default_identity_ttl")
}

Type guard

func ttlOrderingValid(c *ClientIntroduction) bool {
    return c != nil && c.MaxIdentityTTL >= c.DefaultIdentityTTL && c.DefaultIdentityTTL >= 1
}

Prevention

When it happens

Trigger: Config where client_introduction.default_identity_ttl is numerically greater than max_identity_ttl (both individually >= 1), e.g. default 24h with max 1h.

Common situations: Raising default_ttl for longer-lived identities without raising max_ttl; editing one of the two values in automation and not the other; misunderstanding which value must dominate.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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