{"record":{"id":"6f939b73d8bfe06d","repo":"hashicorp/nomad","slug":"shutdowndelay-must-be-a-positive-value","errorCode":null,"errorMessage":"ShutdownDelay must be a positive value","messagePattern":"ShutdownDelay must be a positive value","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":4836,"sourceCode":"\tif j.VersionTag != nil {\n\t\tif len(j.VersionTag.Description) > MaxDescriptionCharacters {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Tagged version description must be under 1000 characters, currently %d\", len(j.VersionTag.Description)))\n\t\t}\n\t}\n\n\t// Check for duplicate task groups\n\ttaskGroups := make(map[string]int)\n\tfor idx, tg := range j.TaskGroups {\n\t\tif tg.Name == \"\" {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Job task group %d missing name\", idx+1))\n\t\t} else if existing, ok := taskGroups[tg.Name]; ok {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Job task group %d redefines '%s' from group %d\", idx+1, tg.Name, existing+1))\n\t\t} else {\n\t\t\ttaskGroups[tg.Name] = idx\n\t\t}\n\n\t\tif tg.ShutdownDelay != nil && *tg.ShutdownDelay < 0 {\n\t\t\tmErr.Errors = append(mErr.Errors, errors.New(\"ShutdownDelay must be a positive value\"))\n\t\t}\n\n\t\tif j.Type == \"system\" && tg.Count > 1 {\n\t\t\tmErr.Errors = append(mErr.Errors,\n\t\t\t\tfmt.Errorf(\"Job task group %s has count %d. Count cannot exceed 1 with system scheduler\",\n\t\t\t\t\ttg.Name, tg.Count))\n\t\t}\n\t}\n\n\t// Validate the task group\n\tfor _, tg := range j.TaskGroups {\n\t\tif err := tg.Validate(j); err != nil {\n\t\t\touter := fmt.Errorf(\"Task group %s validation failed: %v\", tg.Name, err)\n\t\t\tmErr.Errors = append(mErr.Errors, outer)\n\t\t}\n\t}\n\n\t// Validate periodic is only used with batch or sysbatch jobs.","sourceCodeStart":4818,"sourceCodeEnd":4854,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L4818-L4854","documentation":"Nomad job validation rejects a task group whose ShutdownDelay is negative. ShutdownDelay is the time Nomad waits after a task exits before stopping the next group during a rolling update; it must be a positive (well, non-negative; strictly >= 0, error fires only for < 0) duration. It is raised inside Job validation's task-group dedup/validation loop when *tg.ShutdownDelay < 0.","triggerScenarios":"Submitting a job spec (nomad job run / API Job Validate) where a group sets shutdown_delay to a negative duration, e.g. shutdown_delay = \"-5s\".","commonSituations":"Hand-editing HCL and prefixing the value with a minus sign; templating the delay from a computed value that can go negative; misreading the field as a signed offset.","solutions":["Set shutdown_delay to a positive duration value in the task group (e.g. \"5s\").","Remove the shutdown_delay field entirely to use the zero default.","Check templated/env-provided values before injecting them into the spec."],"exampleFix":"// before\ngroup \"web\" {\n  shutdown_delay = \"-5s\"\n}\n// after\ngroup \"web\" {\n  shutdown_delay = \"5s\"\n}","handlingStrategy":"validation","validationCode":"if tg.ShutdownDelay != nil && tg.ShutdownDelay.Seconds() < 0 {\n    return fmt.Errorf(\"shutdown_delay must be >= 0, got %s\", tg.ShutdownDelay)\n}","typeGuard":"func validShutdownDelay(d *time.Duration) bool { return d == nil || *d >= 0 }","tryCatchPattern":null,"preventionTips":["Never prefix duration values with a minus sign in HCL","Validate job specs with `nomad job validate` before submit","Sanitize templated duration inputs"],"tags":["nomad","job-validation","config"],"backgroundTag":"invalid-duration-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"}