hashicorp/nomad · error
retry config backoff %d is greater than default max_backoff
Error message
retry config backoff %d is greater than default max_backoff %d
What it means
RetryConfig.Validate ensures the retry backoff does not exceed the effective max backoff. When MaxBackoff is nil the library defaults max backoff to config.DefaultRetryMaxBackoff (1 minute), so a user-supplied Backoff larger than that default has no valid ceiling and validation fails with this message.
Source
Thrown at client/config/config.go:848
}
// Validate returns an error if the receiver is nil or empty, or if Backoff
// is greater than MaxBackoff.
func (rc *RetryConfig) Validate() error {
// If the config is nil or empty return false so that it is never assigned.
if rc == nil || rc.IsEmpty() {
return errors.New("retry config is nil or empty")
}
// If Backoff not set, no need to validate
if rc.Backoff == nil {
return nil
}
// MaxBackoff nil will end up defaulted to 1 minutes. We should validate that
// the user supplied backoff does not exceed that.
if rc.MaxBackoff == nil && *rc.Backoff > config.DefaultRetryMaxBackoff {
return fmt.Errorf("retry config backoff %d is greater than default max_backoff %d", *rc.Backoff, config.DefaultRetryMaxBackoff)
}
// MaxBackoff == 0 means backoff is unbounded. No need to validate.
if rc.MaxBackoff != nil && *rc.MaxBackoff == 0 {
return nil
}
if rc.MaxBackoff != nil && *rc.Backoff > *rc.MaxBackoff {
return fmt.Errorf("retry config backoff %d is greater than max_backoff %d", *rc.Backoff, *rc.MaxBackoff)
}
return nil
}
// Merge merges two RetryConfigs. The passed instance always takes precedence.
func (rc *RetryConfig) Merge(b *RetryConfig) *RetryConfig {
if rc == nil {
return bView on GitHub (pinned to 482b49bf1a)
Solutions
- Set max_backoff explicitly to a value >= backoff, e.g. backoff="2m" max_backoff="5m"
- Lower backoff to at most the 1-minute default max (e.g. "30s") if unbounded growth is not desired
- Review recent config/version changes that removed a previously present max_backoff
Example fix
// before
retry {
backoff = "2m"
}
// after
retry {
backoff = "2m"
max_backoff = "5m"
} Defensive patterns
Strategy: validation
Validate before calling
const defaultMaxBackoff = time.Minute
if rc.Backoff != nil && rc.MaxBackoff == nil && *rc.Backoff > defaultMaxBackoff {
return fmt.Errorf("backoff %s exceeds default max_backoff %s; set max_backoff", *rc.Backoff, defaultMaxBackoff)
} Type guard
func backoffWithinDefaultMax(rc *config.RetryConfig, def time.Duration) bool {
return rc == nil || rc.Backoff == nil || (rc.MaxBackoff != nil) || *rc.Backoff <= def
} Try / catch
if err := rc.Validate(); err != nil {
if strings.Contains(err.Error(), "greater than default max_backoff") {
rc.MaxBackoff = ptr(time.Duration(*rc.Backoff) * 2)
err = rc.Validate()
}
return err
} Prevention
- Whenever backoff > 1m, always set max_backoff explicitly
- Re-check retry blocks after upgrading, since default max may change
- Validate merged configs, not just individual files
When it happens
Trigger: Calling RetryConfig.Validate when Backoff is set (e.g. 120000000000 ns = 2m), MaxBackoff is nil, and *Backoff > config.DefaultRetryMaxBackoff, e.g. backoff="2m" with no max_backoff in the config block.
Common situations: retry { backoff = ... } set to a value above 1m without also setting max_backoff in the agent config; copying a retry block that previously had max_backoff into a config where it was dropped; defaults changing between library versions so a formerly valid backoff now exceeds the default.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- retry config backoff %d is greater than max_backoff %d
- retry config is nil or empty
- wait config min %d is greater than max %d
- wait config is nil or empty
- fingerprint name cannot be empty
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/0172956587d716f1.
Report an issue: GitHub.