hashicorp/nomad · error
stop_after cannot be a negative duration
Error message
stop_after cannot be a negative duration
What it means
errNegativeStopAfter is a disconnect-strategy validation error: stop_after must be zero or a positive duration. A negative stop_after would mean stopping the task before the disconnect happens, so DisconnectStrategy.Validate rejects the job when *ds.StopOnClientAfter < 0.
Source
Thrown at nomad/structs/group.go:28
"github.com/hashicorp/go-multierror"
)
const (
// ReconcileOption is used to specify the behavior of the reconciliation process
// between the original allocations and the replacements when a previously
// disconnected client comes back online.
ReconcileOptionKeepOriginal = "keep_original"
ReconcileOptionKeepReplacement = "keep_replacement"
ReconcileOptionBestScore = "best_score"
ReconcileOptionLongestRunning = "longest_running"
)
var (
// Disconnect strategy validation errors
errStopAndLost = errors.New("Disconnect cannot be configured with both lost_after and stop_after")
errNegativeLostAfter = errors.New("lost_after cannot be a negative duration")
errNegativeStopAfter = errors.New("stop_after cannot be a negative duration")
errStopAfterNonService = errors.New("stop_after can only be used with service or batch job types")
errInvalidReconcile = errors.New("reconcile option is invalid")
)
func NewDefaultDisconnectStrategy() *DisconnectStrategy {
return &DisconnectStrategy{
Replace: new(true),
Reconcile: ReconcileOptionBestScore,
}
}
// Disconnect strategy defines how both clients and server should behave in case of
// disconnection between them.
type DisconnectStrategy struct {
// Defines for how long the server will consider the unresponsive node as
// disconnected but alive instead of lost.
LostAfter time.Duration `mapstructure:"lost_after" hcl:"lost_after,optional"`
View on GitHub (pinned to 482b49bf1a)
Solutions
- Set stop_after to a positive duration (e.g. "30m") or remove it to disable stop-on-disconnect
- Clamp or abs() any computed duration used in the job template
- Validate the job with 'nomad job validate' before submission
Example fix
// before
disconnect {
stop_after = "-30m"
}
// after
disconnect {
stop_after = "30m"
} Defensive patterns
Strategy: validation
Validate before calling
if ds := grp.Disconnect; ds != nil && ds.StopOnClientAfter != nil && *ds.StopOnClientAfter < 0 {
return fmt.Errorf("disconnect: stop_after must be >= 0")
} Type guard
func stopAfterValid(ds *api.DisconnectStrategy) bool {
return ds == nil || ds.StopOnClientAfter == nil || *ds.StopOnClientAfter >= 0
} Try / catch
err := client.Jobs().Validate(job, nil, nil)
if err != nil && strings.Contains(err.Error(), "stop_after cannot be a negative duration") {
return fmt.Errorf("fix stop_after to a positive duration: %w", err)
} Prevention
- Clamp or abs() computed durations before templating stop_after
- Add CI validation via 'nomad job validate' for all job specs
- Use explicit positive literals for stop_after instead of derived values when possible
When it happens
Trigger: Submitting a job whose group disconnect block sets stop_after to a negative duration, checked at group.go:75 in DisconnectStrategy.Validate (only when StopOnClientAfter is non-nil).
Common situations: Typos like stop_after = "-30m"; templated durations computed from data that can be negative; mixing up sign when converting between seconds/nanoseconds in generated job specs.
Related errors
- Disconnect cannot be configured with both lost_after and sto
- lost_after cannot be a negative duration
- Missing job ID
- Job ID contains a space
- Missing job name
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/3f7e50a052b2ee66.
Report an issue: GitHub.