hashicorp/nomad · error

Nomad can't restart the TaskGroup %v times in an interval of

Error message

Nomad can't restart the TaskGroup %v times in an interval of %v with a delay of %v

What it means

RestartPolicy.Validate() requires that attempts * delay fit within interval. If the product of the restart attempts and the delay between them exceeds the interval, Nomad could not physically perform the configured restarts in the window, so the policy is rejected as mathematically impossible.

Source

Thrown at nomad/structs/structs.go:6583

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 {
	switch jobType {
	case JobTypeService, JobTypeSystem:
		rp := DefaultServiceJobRestartPolicy
		return &rp
	case JobTypeBatch:
		rp := DefaultBatchJobRestartPolicy
		return &rp
	}
	return nil
}

const ReschedulePolicyMinInterval = 15 * time.Second
const ReschedulePolicyMinDelay = 1 * time.Second

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Increase interval so it is >= attempts * delay.
  2. Reduce attempts or delay until the product fits the interval.
  3. Validate the arithmetic: e.g. attempts=5, delay=15s needs interval >= 75s.

Example fix

// before
restart {
  interval = "30m"
  attempts = 5
  delay    = "10m"
}
// after
restart {
  interval = "1h"
  attempts = 5
  delay    = "10m"
}
Defensive patterns

Strategy: validation

Validate before calling

if rp != nil && time.Duration(rp.Attempts)*rp.Delay > rp.Interval {
    return fmt.Errorf("attempts*delay (%v) exceeds interval (%v)", time.Duration(rp.Attempts)*rp.Delay, rp.Interval)
}

Prevention

When it happens

Trigger: A restart block where time.Duration(attempts) * delay > interval, e.g. attempts = 5, delay = "10m", interval = "30m" (50m > 30m).

Common situations: Tuning attempts upward after lowering interval, or setting a long delay for backoff without recomputing the interval; very common after scaling attempts for flaky services.

Related errors


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