hashicorp/nomad · error
If Attempts >0, Unlimited cannot also be set to true
Error message
If Attempts >0, Unlimited cannot also be set to true
What it means
A reschedule policy that sets Unlimited=true together with Attempts>0 is contradictory: unlimited rescheduling means no attempt cap. ValidateReschedulePolicy in nomad/structs appends this error when r.Attempts > 0 and r.Unlimited are both set.
Source
Thrown at nomad/structs/structs.go:6660
// Validate uses different criteria to validate the reschedule policy
// Delay must be a minimum of 1 second
// Delay Ceiling is ignored if Delay Function is "constant"
// Number of possible attempts is validated, given the interval, delay and delay function
func (r *ReschedulePolicy) Validate() error {
if !r.Enabled() {
return nil
}
var mErr multierror.Error
// Check for ambiguous/confusing settings
if r.Attempts > 0 {
if r.Interval <= 0 {
_ = multierror.Append(&mErr, fmt.Errorf("Interval must be a non zero value if Attempts > 0"))
}
if r.Unlimited {
_ = multierror.Append(&mErr, fmt.Errorf("Reschedule Policy with Attempts = %v, Interval = %v, "+
"and Unlimited = %v is ambiguous", r.Attempts, r.Interval, r.Unlimited))
_ = multierror.Append(&mErr, errors.New("If Attempts >0, Unlimited cannot also be set to true"))
}
}
delayPreCheck := true
// Delay should be bigger than the default
if r.Delay.Nanoseconds() < ReschedulePolicyMinDelay.Nanoseconds() {
_ = multierror.Append(&mErr, fmt.Errorf("Delay cannot be less than %v (got %v)", ReschedulePolicyMinDelay, r.Delay))
delayPreCheck = false
}
// Must use a valid delay function
if !isValidDelayFunction(r.DelayFunction) {
_ = multierror.Append(&mErr, fmt.Errorf("Invalid delay function %q, must be one of %q", r.DelayFunction, RescheduleDelayFunctions))
delayPreCheck = false
}
// Validate MaxDelay if not using linear delay progression
if r.DelayFunction != "constant" {View on GitHub (pinned to 482b49bf1a)
Solutions
- Set unlimited = false (default) so attempts/interval take effect.
- Or remove attempts and interval, leaving unlimited = true.
- Use nomad job validate to check the spec before submission.
Example fix
// before
reschedule {
attempts = 5
interval = "30m"
unlimited = true
}
// after
reschedule {
attempts = 5
interval = "30m"
} Defensive patterns
Strategy: validation
Validate before calling
if rp.Attempts > 0 && rp.Unlimited {
return errors.New("reschedule policy: attempts>0 and unlimited=true are mutually exclusive")
} Type guard
func isUnambiguousReschedule(r *structs.ReschedulePolicy) bool { return !r.Unlimited || r.Attempts == 0 } Prevention
- Pick one mode: either unlimited=true OR attempts+interval
- Never merge reschedule policy fragments from different sources
- Run nomad job validate in CI for every job spec
When it happens
Trigger: Submitting a job whose group reschedule policy has attempts > 0 and unlimited = true; constructing structs.ReschedulePolicy directly with both fields set.
Common situations: Merging config fragments where one sets unlimited=true and another sets attempts; copying a sample policy and toggling both knobs; upgrading specs written before the validation existed.
Related errors
- failed to parse config:
- only one of cgroups_v1_override and cgroups_v2_override may
- work_dir must be an absolute path
- require only one of PemKey or PemKeyFile
- missing PemCert, PemCertFile, or KeyID
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/e6b7e542e861e8c8.
Report an issue: GitHub.