hashicorp/nomad · error

Nomad can only make %v attempts in %v with initial delay %v

Error message

Nomad can only make %v attempts in %v with initial delay %v and delay function %q

What it means

ReschedulePolicy.Validate calls viableAttempts() which computes how many retries actually fit in the configured Interval given the Delay, DelayFunction and MaxDelay. If the retry budget (Attempts) cannot be achieved within Interval, this error is thrown for constant delay functions. It tells you the real number of attempts possible so you can correct the policy.

Source

Thrown at nomad/structs/structs.go:6723

}

func isValidDelayFunction(delayFunc string) bool {
	for _, value := range RescheduleDelayFunctions {
		if value == delayFunc {
			return true
		}
	}
	return false
}

func (r *ReschedulePolicy) validateDelayParams() error {
	ok, possibleAttempts, recommendedInterval := r.viableAttempts()
	if ok {
		return nil
	}
	var mErr multierror.Error
	if r.DelayFunction == "constant" {
		_ = multierror.Append(&mErr, fmt.Errorf("Nomad can only make %v attempts in %v with initial delay %v and "+
			"delay function %q", possibleAttempts, r.Interval, r.Delay, r.DelayFunction))
	} else {
		_ = multierror.Append(&mErr, fmt.Errorf("Nomad can only make %v attempts in %v with initial delay %v, "+
			"delay function %q, and delay ceiling %v", possibleAttempts, r.Interval, r.Delay, r.DelayFunction, r.MaxDelay))
	}
	_ = multierror.Append(&mErr, fmt.Errorf("Set the interval to at least %v to accommodate %v attempts", recommendedInterval.Round(time.Second), r.Attempts))
	return mErr.ErrorOrNil()
}

func (r *ReschedulePolicy) viableAttempts() (bool, int, time.Duration) {
	var possibleAttempts int
	var recommendedInterval time.Duration
	valid := true
	switch r.DelayFunction {
	case "constant":
		recommendedInterval = time.Duration(r.Attempts) * r.Delay
		if r.Interval < recommendedInterval {
			possibleAttempts = int(r.Interval / r.Delay)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Increase interval so that interval >= attempts * delay for constant delay functions.
  2. Reduce attempts to the number reported as possibleAttempts in the error.
  3. Reduce the initial delay so all attempts fit in the interval.
  4. Set unlimited: true to skip this accounting check.
  5. Use the recommendedInterval from the companion error to size the interval correctly.

Example fix

// before
reschedule {
  attempts = 5
  interval = "20m"
  delay    = "10m"
  delay_function = "constant"
}
// after
reschedule {
  attempts = 5
  interval = "50m"
  delay    = "10m"
  delay_function = "constant"
}
Defensive patterns

Strategy: validation

Validate before calling

func constantDelayViable(p *structs.ReschedulePolicy) error {
	if p.DelayFunction != "constant" || p.Unlimited {
		return nil
	}
	if need := time.Duration(p.Attempts) * p.Delay; need > p.Interval {
		return fmt.Errorf("need interval >= %v, have %v", need, p.Interval)
	}
	return nil
}

Type guard

func constantDelayFits(p *structs.ReschedulePolicy) bool {
	return p.Unlimited || p.DelayFunction != "constant" || time.Duration(p.Attempts)*p.Delay <= p.Interval
}

Try / catch

if err := policy.Validate(); err != nil {
	if strings.Contains(err.Error(), "delay function \"constant\"") {
		// enlarge interval or reduce attempts/delay, then retry submit
	}
}

Prevention

When it happens

Trigger: Submitting a job with reschedule.delay_function = "constant" where Delay * Attempts > Interval (i.e. possibleAttempts < r.Attempts), and unlimited is false. Example: attempts=5, delay=10m, interval=20m — only 2 attempts fit.

Common situations: Users set generous delays but a short interval, expecting all attempts to fire; upgrading Nomad after stricter validation was added; auto-generated policies where interval and delay were configured independently.

Related errors


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