hashicorp/nomad · error

Unsupported restart mode: %q

Error message

Unsupported restart mode: %q

What it means

RestartPolicy.Validate() in nomad/structs/structs.go rejects a restart policy whose Mode is neither "delay" nor "fail". Nomad only supports these two restart modes; anything else (typo, wrong case, empty string) fails job validation before the job is registered. It is appended to a multierror and surfaced with the rest of the job validation errors.

Source

Thrown at nomad/structs/structs.go:6570

	// RenderTemplates is flag to explicitly render all templates on task restart
	RenderTemplates bool
}

func (r *RestartPolicy) Copy() *RestartPolicy {
	if r == nil {
		return nil
	}
	nrp := new(RestartPolicy)
	*nrp = *r
	return nrp
}

func (r *RestartPolicy) Validate() error {
	var mErr multierror.Error
	switch r.Mode {
	case RestartPolicyModeDelay, RestartPolicyModeFail:
	default:
		_ = multierror.Append(&mErr, fmt.Errorf("Unsupported restart mode: %q", r.Mode))
	}

	// Check for ambiguous/confusing settings
	if r.Attempts == 0 && r.Mode != RestartPolicyModeFail {
		_ = multierror.Append(&mErr, fmt.Errorf("Restart policy %q with %d attempts is ambiguous", r.Mode, r.Attempts))
	}

	if r.Interval.Nanoseconds() < RestartPolicyMinInterval.Nanoseconds() {
		_ = multierror.Append(&mErr, fmt.Errorf("Interval can not be less than %v (got %v)", RestartPolicyMinInterval, r.Interval))
	}
	if time.Duration(r.Attempts)*r.Delay > r.Interval {
		_ = multierror.Append(&mErr,
			fmt.Errorf("Nomad can't restart the TaskGroup %v times in an interval of %v with a delay of %v", r.Attempts, r.Interval, r.Delay))
	}
	return mErr.ErrorOrNil()
}

func NewRestartPolicy(jobType string) *RestartPolicy {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set restart_policy.mode to exactly "delay" (default) or "fail" in the task group.
  2. Run `nomad job validate <file>` or POST to /v1/validate before submitting to catch the typo.
  3. Check casing: values are lowercase and quoted in HCL/JSON.

Example fix

// before
restart {
  interval = "30m"
  attempts = 2
  mode     = "always"
}
// after
restart {
  interval = "30m"
  attempts = 2
  mode     = "delay"
}
Defensive patterns

Strategy: validation

Validate before calling

validModes := map[string]bool{"delay": true, "fail": true}
if rp := tg.RestartPolicy; rp != nil && !validModes[rp.Mode] {
    return fmt.Errorf("restart_policy.mode %q must be \"delay\" or \"fail\"", rp.Mode)
}

Type guard

func validRestartMode(m string) bool { return m == "delay" || m == "fail" }

Prevention

When it happens

Trigger: Submitting a job (POST /v1/jobs) or validating one (POST /v1/validate) whose task group's restart_policy.mode is set to any string other than "delay" or "fail", e.g. "always", "never", "Delay", or an empty value.

Common situations: Copy-pasting restart config from another orchestrator (e.g. Docker's or Kubernetes' restart vocabulary), typos like "restrat" or "delay-mode", YAML/HCL key confusion that leaves mode empty, or upgrading from an older/custom build that accepted other modes.

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/100215315e545505. Report an issue: GitHub.