hashicorp/nomad · error

timeout cannot be negative

Error message

timeout cannot be negative

What it means

NewEvalBroker validates that the nack timeout is non-negative before constructing the broker. The nack timeout governs how long a dequeued evaluation can go unacknowledged before being requeued; a negative value is meaningless and is rejected at construction time. This is a programming/configuration error, not a runtime condition.

Source

Thrown at nomad/eval_broker.go:148

// ReadyEvaluations is a list of ready evaluations across multiple jobs. We
// implement the container/heap interface so that this is a priority queue.
type ReadyEvaluations []*structs.Evaluation

// PendingEvaluations is a list of pending evaluations for a given job. We
// implement the container/heap interface so that this is a priority queue.
type PendingEvaluations []*structs.Evaluation

// NewEvalBroker creates a new evaluation broker. This is parameterized
// with the timeout used for messages that are not acknowledged before we
// assume a Nack and attempt to redeliver as well as the deliveryLimit
// which prevents a failing eval from being endlessly delivered. The
// initialNackDelay is the delay before making a Nacked evaluation available
// again for the first Nack and subsequentNackDelay is the compounding delay
// after the first Nack.
func NewEvalBroker(ctx context.Context, timeout, initialNackDelay, subsequentNackDelay time.Duration, deliveryLimit int) (*EvalBroker, error) {
	if timeout < 0 {
		return nil, fmt.Errorf("timeout cannot be negative")
	}
	b := &EvalBroker{
		nackTimeout:          timeout,
		deliveryLimit:        deliveryLimit,
		enabled:              false,
		enabledNotifier:      broker.NewGenericNotifier(ctx),
		stats:                new(BrokerStats),
		evals:                make(map[string]int),
		jobEvals:             make(map[structs.NamespacedID]string),
		pending:              make(map[structs.NamespacedID]PendingEvaluations),
		cancelable:           make([]*structs.Evaluation, 0, structs.MaxUUIDsPerWriteRequest),
		ready:                make(map[string]ReadyEvaluations),
		unack:                make(map[string]*unackEval),
		waiting:              make(map[string]chan struct{}),
		requeue:              make(map[string]*structs.Evaluation),
		timeWait:             make(map[string]*time.Timer),
		initialNackDelay:     initialNackDelay,
		subsequentNackDelay:  subsequentNackDelay,

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Pass a positive timeout, e.g. time.Minute (the Nomad default is 1 minute).
  2. Validate the server config value before calling NewServer and reject negatives with a clear message.
  3. If the intent is 'no nack timeout', pass 0 or the maximum duration, not a negative value.
  4. Fix parsing of the config value (ensure time.ParseDuration output isn't negated).

Example fix

// before
b, err := NewEvalBroker(ctx, -1*time.Second, nackDelay, subDelay, limit)
// after
timeout := 1 * time.Minute
b, err := NewEvalBroker(ctx, timeout, nackDelay, subDelay, limit)
Defensive patterns

Strategy: validation

Validate before calling

if nackTimeout < 0 {
	return fmt.Errorf("nack timeout must be >= 0, got %s", nackTimeout)
}
broker, err := NewEvalBroker(ctx, nackTimeout, initDelay, subDelay, limit)

Prevention

When it happens

Trigger: Calling NewEvalBroker (directly in tests like dummyFSM/testBrokerFromConfig, or via NewServer) with a negative time.Duration for the timeout parameter, typically from a config where TimeoutNack = -1 or an unvalidated user-supplied duration.

Common situations: Operator sets a negative value in server config for evaluation nack timeout; a test harness passes -1 to mean 'disabled'; integer/decimal parsing mistakes turning '-1s' into a negative duration.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/75d0ee7361bf03a9. Report an issue: GitHub.