hashicorp/nomad · error
client_introduction.max_identity_ttl must be greater one
Error message
client_introduction.max_identity_ttl must be greater one
What it means
client_introduction validation also requires `max_identity_ttl` to be at least 1, mirroring the default TTL check. A zero or negative maximum identity lifetime is invalid because the agent could never issue any valid identity. This check runs before the max>=default comparison.
Source
Thrown at command/agent/config.go:1272
func (c *ClientIntroduction) Validate() error {
if c == nil {
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.View on GitHub (pinned to 482b49bf1a)
Solutions
- Set `max_identity_ttl` to a positive duration, e.g. "24h".
- Ensure max_identity_ttl >= default_identity_ttl so the subsequent check also passes.
- If 0 was meant to signal 'unlimited', use the largest supported duration instead.
Example fix
// before
client_introduction {
enforcement = "serve-and-mark"
default_identity_ttl = "1h"
max_identity_ttl = 0
}
// after
client_introduction {
enforcement = "serve-and-mark"
default_identity_ttl = "1h"
max_identity_ttl = "24h"
} Defensive patterns
Strategy: validation
Validate before calling
if c := cfg.ClientIntroduction; c != nil && c.MaxIdentityTTL < 1 {
return errors.New("client_introduction.max_identity_ttl must be >= 1")
} Type guard
func validMaxTTL(c *ClientIntroduction) bool { return c != nil && c.MaxIdentityTTL >= 1 } Prevention
- Set max_identity_ttl alongside default_identity_ttl as a pair.
- Avoid 0/negative values; 0 is not 'unlimited'.
- Keep duration units explicit in generated configs.
When it happens
Trigger: Config sets `client_introduction.max_identity_ttl` to 0 or a negative value (or parses to < 1) while enforcement is valid and default_identity_ttl passes its own check.
Common situations: Setting max_ttl = 0 intending 'unlimited'; copy/paste dropping the value; unit mismatch making the intended duration parse as zero.
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
- client_introduction.default_identity_ttl must be greater one
- client_introduction.max_identity_ttl must be greater than de
- client_introduction.enforcement must be set
- failed to parse config:
- rpc.dial_timeout must be greater than or equal to zero
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/8210da8befd359f6.
Report an issue: GitHub.