{"record":{"id":"f5448466483ac055","repo":"hashicorp/nomad","slug":"retry-config-is-nil-or-empty","errorCode":null,"errorMessage":"retry config is nil or empty","messagePattern":"retry config is nil or empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/config/config.go","lineNumber":837,"sourceCode":"func (rc *RetryConfig) Equal(other *RetryConfig) bool {\n\treturn reflect.DeepEqual(rc, other)\n}\n\n// IsEmpty returns true if the receiver only contains an instance with no fields set.\nfunc (rc *RetryConfig) IsEmpty() bool {\n\tif rc == nil {\n\t\treturn true\n\t}\n\n\treturn rc.Equal(&RetryConfig{})\n}\n\n// Validate returns an error if the receiver is nil or empty, or if Backoff\n// is greater than  MaxBackoff.\nfunc (rc *RetryConfig) Validate() error {\n\t// If the config is nil or empty return false so that it is never assigned.\n\tif rc == nil || rc.IsEmpty() {\n\t\treturn errors.New(\"retry config is nil or empty\")\n\t}\n\n\t// If Backoff not set, no need to validate\n\tif rc.Backoff == nil {\n\t\treturn nil\n\t}\n\n\t// MaxBackoff nil will end up defaulted to 1 minutes. We should validate that\n\t// the user supplied backoff does not exceed that.\n\tif rc.MaxBackoff == nil && *rc.Backoff > config.DefaultRetryMaxBackoff {\n\t\treturn fmt.Errorf(\"retry config backoff %d is greater than default max_backoff %d\", *rc.Backoff, config.DefaultRetryMaxBackoff)\n\t}\n\n\t// MaxBackoff == 0 means backoff is unbounded. No need to validate.\n\tif rc.MaxBackoff != nil && *rc.MaxBackoff == 0 {\n\t\treturn nil\n\t}\n","sourceCodeStart":819,"sourceCodeEnd":855,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/config/config.go#L819-L855","documentation":"This error comes from RetryConfig.Validate() in the client config package. It means the RetryConfig being validated is either nil or has no fields set (IsEmpty() returns true), so it is not a usable retry configuration and is rejected rather than being assigned/used. The library throws it to prevent silently running with a meaningless retry policy.","triggerScenarios":"Calling RetryConfig.Validate() on a nil *RetryConfig, or on a zero-valued RetryConfig{} (e.g. constructed via var rc RetryConfig or &RetryConfig{} without setting any fields) during config validation.","commonSituations":"Hand-written client/HCL/JSON config where a retry block exists but is empty; programmatically building a RetryConfig but forgetting to set Backoff or interval fields; config decoding that yields a non-nil struct with all zero values.","solutions":["Set at least one retry field (e.g. Attempts, Backoff/delay) on the RetryConfig before validating","If retries are not wanted, remove the empty retry block or pass nil and skip assignment instead of validating an empty config","Check that config decoding actually populated the retry section (look for typos in keys, wrong nesting, or wrong env var names)"],"exampleFix":"// before\nrc := &RetryConfig{}\nif err := rc.Validate(); err != nil { ... } // retry config is nil or empty\n// after\nrc := &RetryConfig{Attempts: 3, Backoff: 500 * time.Millisecond, MaxBackoff: 30 * time.Second}\nif err := rc.Validate(); err != nil { ... }","handlingStrategy":"validation","validationCode":"func validRetry(rc *RetryConfig) bool { return rc != nil && !rc.IsEmpty() }","typeGuard":"if rc == nil || rc.IsEmpty() {\n    // treat as \"no retry config\": skip assignment or substitute defaults\n}","tryCatchPattern":"if err := rc.Validate(); err != nil {\n    log.Printf(\"retry config invalid: %v; using defaults\", err)\n    rc = defaultRetryConfig\n}","preventionTips":["Always construct RetryConfig with at least Backoff/Attempts set before validating","Use a helper/constructor that fills defaults instead of zero-valued structs","Add a config-load test asserting the retry section decodes non-empty","Skip assignment (per the comment in Validate) rather than storing an empty config"],"tags":["config","validation","retry"],"backgroundTag":"invalid-config-validation","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}