{"record":{"id":"100215315e545505","repo":"hashicorp/nomad","slug":"unsupported-restart-mode-q","errorCode":null,"errorMessage":"Unsupported restart mode: %q","messagePattern":"Unsupported restart mode: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":6570,"sourceCode":"\t// RenderTemplates is flag to explicitly render all templates on task restart\n\tRenderTemplates bool\n}\n\nfunc (r *RestartPolicy) Copy() *RestartPolicy {\n\tif r == nil {\n\t\treturn nil\n\t}\n\tnrp := new(RestartPolicy)\n\t*nrp = *r\n\treturn nrp\n}\n\nfunc (r *RestartPolicy) Validate() error {\n\tvar mErr multierror.Error\n\tswitch r.Mode {\n\tcase RestartPolicyModeDelay, RestartPolicyModeFail:\n\tdefault:\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"Unsupported restart mode: %q\", r.Mode))\n\t}\n\n\t// Check for ambiguous/confusing settings\n\tif r.Attempts == 0 && r.Mode != RestartPolicyModeFail {\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"Restart policy %q with %d attempts is ambiguous\", r.Mode, r.Attempts))\n\t}\n\n\tif r.Interval.Nanoseconds() < RestartPolicyMinInterval.Nanoseconds() {\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"Interval can not be less than %v (got %v)\", RestartPolicyMinInterval, r.Interval))\n\t}\n\tif time.Duration(r.Attempts)*r.Delay > r.Interval {\n\t\t_ = multierror.Append(&mErr,\n\t\t\tfmt.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))\n\t}\n\treturn mErr.ErrorOrNil()\n}\n\nfunc NewRestartPolicy(jobType string) *RestartPolicy {","sourceCodeStart":6552,"sourceCodeEnd":6588,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L6552-L6588","documentation":"RestartPolicy.Validate() in nomad/structs/structs.go rejects a restart policy whose Mode is neither \"delay\" nor \"fail\". Nomad only supports these two restart modes; anything else (typo, wrong case, empty string) fails job validation before the job is registered. It is appended to a multierror and surfaced with the rest of the job validation errors.","triggerScenarios":"Submitting a job (POST /v1/jobs) or validating one (POST /v1/validate) whose task group's restart_policy.mode is set to any string other than \"delay\" or \"fail\", e.g. \"always\", \"never\", \"Delay\", or an empty value.","commonSituations":"Copy-pasting restart config from another orchestrator (e.g. Docker's or Kubernetes' restart vocabulary), typos like \"restrat\" or \"delay-mode\", YAML/HCL key confusion that leaves mode empty, or upgrading from an older/custom build that accepted other modes.","solutions":["Set restart_policy.mode to exactly \"delay\" (default) or \"fail\" in the task group.","Run `nomad job validate <file>` or POST to /v1/validate before submitting to catch the typo.","Check casing: values are lowercase and quoted in HCL/JSON."],"exampleFix":"// before\nrestart {\n  interval = \"30m\"\n  attempts = 2\n  mode     = \"always\"\n}\n// after\nrestart {\n  interval = \"30m\"\n  attempts = 2\n  mode     = \"delay\"\n}","handlingStrategy":"validation","validationCode":"validModes := map[string]bool{\"delay\": true, \"fail\": true}\nif rp := tg.RestartPolicy; rp != nil && !validModes[rp.Mode] {\n    return fmt.Errorf(\"restart_policy.mode %q must be \\\"delay\\\" or \\\"fail\\\"\", rp.Mode)\n}","typeGuard":"func validRestartMode(m string) bool { return m == \"delay\" || m == \"fail\" }","tryCatchPattern":null,"preventionTips":["Only ever write mode = \"delay\" or mode = \"fail\" in job files.","Run `nomad job validate` in CI before every job submit.","Reuse the structs.RestartPolicyMode* constants when building policies in Go."],"tags":["nomad","validation","job-spec","restart-policy"],"backgroundTag":"invalid-enum-value","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"}