hashicorp/nomad · error
ShutdownDelay must be a positive value
Error message
ShutdownDelay must be a positive value
What it means
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.
Source
Thrown at nomad/structs/structs.go:4836
if j.VersionTag != nil {
if len(j.VersionTag.Description) > MaxDescriptionCharacters {
mErr.Errors = append(mErr.Errors, fmt.Errorf("Tagged version description must be under 1000 characters, currently %d", len(j.VersionTag.Description)))
}
}
// Check for duplicate task groups
taskGroups := make(map[string]int)
for idx, tg := range j.TaskGroups {
if tg.Name == "" {
mErr.Errors = append(mErr.Errors, fmt.Errorf("Job task group %d missing name", idx+1))
} else if existing, ok := taskGroups[tg.Name]; ok {
mErr.Errors = append(mErr.Errors, fmt.Errorf("Job task group %d redefines '%s' from group %d", idx+1, tg.Name, existing+1))
} else {
taskGroups[tg.Name] = idx
}
if tg.ShutdownDelay != nil && *tg.ShutdownDelay < 0 {
mErr.Errors = append(mErr.Errors, errors.New("ShutdownDelay must be a positive value"))
}
if j.Type == "system" && tg.Count > 1 {
mErr.Errors = append(mErr.Errors,
fmt.Errorf("Job task group %s has count %d. Count cannot exceed 1 with system scheduler",
tg.Name, tg.Count))
}
}
// Validate the task group
for _, tg := range j.TaskGroups {
if err := tg.Validate(j); err != nil {
outer := fmt.Errorf("Task group %s validation failed: %v", tg.Name, err)
mErr.Errors = append(mErr.Errors, outer)
}
}
// Validate periodic is only used with batch or sysbatch jobs.View on GitHub (pinned to 482b49bf1a)
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.
Example fix
// before
group "web" {
shutdown_delay = "-5s"
}
// after
group "web" {
shutdown_delay = "5s"
} Defensive patterns
Strategy: validation
Validate before calling
if tg.ShutdownDelay != nil && tg.ShutdownDelay.Seconds() < 0 {
return fmt.Errorf("shutdown_delay must be >= 0, got %s", tg.ShutdownDelay)
} Type guard
func validShutdownDelay(d *time.Duration) bool { return d == nil || *d >= 0 } Prevention
- Never prefix duration values with a minus sign in HCL
- Validate job specs with `nomad job validate` before submit
- Sanitize templated duration inputs
When it happens
Trigger: 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".
Common situations: 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.
Related errors
- stop_after can only be used with service or batch job types
- plugin not found
- wait config is nil or empty
- wait config is empty
- ErrConnectRequireOneNetwork
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/6f939b73d8bfe06d.
Report an issue: GitHub.