hashicorp/nomad · error

client_introduction.enforcement must be set

Error message

client_introduction.enforcement must be set

What it means

The `client_introduction` block requires an `enforcement` setting that selects how the agent handles client auto-introduction. Validate() refuses to continue when `Enforcement` is the empty string because the behavior would otherwise be undefined. A second check (next error) verifies the value is one of the known ClientIntroductionEnforcementValues.

Source

Thrown at command/agent/config.go:1261

		result.MaxIdentityTTL = z.MaxIdentityTTL
	}
	if len(z.ExtraKeysHCL) > 0 {
		result.ExtraKeysHCL = append(result.ExtraKeysHCL, z.ExtraKeysHCL...)
	}

	return &result
}

// Validate performs validation on the ClientIntroduction configuration block to
// ensure the values are set correctly for use by the server.
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
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Add `enforcement = "<one of the supported values>"` inside the client_introduction block (see ClientIntroductionEnforcementValues for valid options).
  2. If you don't need client introduction at all, remove the entire client_introduction block.
  3. Check the key spelling and that it is nested inside client_introduction, not a sibling block.

Example fix

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

// after
client_introduction {
  enforcement           = "serve-and-mark"
  default_identity_ttl  = "1h"
}
Defensive patterns

Strategy: validation

Validate before calling

if cfg.ClientIntroduction != nil && cfg.ClientIntroduction.Enforcement == "" {
    return errors.New("client_introduction.enforcement must be set before starting the agent")
}
if cfg.ClientIntroduction != nil && !slices.Contains(ClientIntroductionEnforcementValues, cfg.ClientIntroduction.Enforcement) {
    return fmt.Errorf("enforcement must be one of %v", ClientIntroductionEnforcementValues)
}

Type guard

func enforcementSet(c *ClientIntroduction) bool {
    return c != nil && slices.Contains(ClientIntroductionEnforcementValues, c.Enforcement)
}

Prevention

When it happens

Trigger: Agent config defines a `client_introduction { ... }` block but omits the `enforcement` key, so the parsed struct's Enforcement field is "" when its Validate() runs during agent startup/config parse.

Common situations: Adding a client_introduction stanza after reading docs for an older version that defaulted enforcement; renaming the key (e.g. `mode` instead of `enforcement`); YAML/HCL indentation mistakes leaving enforcement outside the block.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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