nats-io/nats-server · error · ApiError
inactive_threshold must not be negative
Error message
inactive_threshold must not be negative
What it means
A JetStream pedantic validation error thrown when InactiveThreshold (the time after which an inactive ephemeral consumer is deleted) is negative. It must be 0 (use default) or a positive duration; pedantic mode rejects the config instead of clamping to 0 at server/consumer.go:658.
Source
Thrown at server/consumer.go:658
return NewJSPedanticError(errors.New("max_expires must not be negative"))
}
config.MaxRequestExpires = 0
}
if config.MaxRequestMaxBytes < 0 {
if pedantic {
return NewJSPedanticError(errors.New("max_bytes must not be negative"))
}
config.MaxRequestMaxBytes = 0
}
if config.Heartbeat < 0 {
if pedantic {
return NewJSPedanticError(errors.New("idle_heartbeat must not be negative"))
}
config.Heartbeat = 0
}
if config.InactiveThreshold < 0 {
if pedantic {
return NewJSPedanticError(errors.New("inactive_threshold must not be negative"))
}
config.InactiveThreshold = 0
}
if config.PinnedTTL < 0 {
if pedantic {
return NewJSPedanticError(errors.New("priority_timeout must not be negative"))
}
config.PinnedTTL = 0
}
// Set to default if not specified.
if config.DeliverSubject == _EMPTY_ && config.MaxWaiting == 0 {
config.MaxWaiting = JSWaitQueueDefaultMax
}
// Setup proper default for ack wait if we are in explicit ack mode.
if config.AckWait == 0 && (config.AckPolicy == AckExplicit || config.AckPolicy == AckAll) {
config.AckWait = JsAckWaitDefault
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Set InactiveThreshold to 0 for the default or a positive duration (e.g. 5 * time.Minute).
- Clamp computed durations to >= 0 before assignment.
- If 'never expire' is intended, use a very large duration instead of a negative one.
- Validate the config client-side with Validate(true).
Example fix
// before
cc := nats.ConsumerConfig{InactiveThreshold: -1 * time.Minute}
// after
cc := nats.ConsumerConfig{InactiveThreshold: 5 * time.Minute} Defensive patterns
Strategy: validation
Validate before calling
if cfg.InactiveThreshold < 0 { return errors.New("inactive_threshold must not be negative") } Try / catch
if _, err := js.AddConsumer(stream, &cc); err != nil && strings.Contains(err.Error(), "inactive_threshold must not be negative") {
cc.InactiveThreshold = 0
_, err = js.AddConsumer(stream, &cc)
} Prevention
- For 'never expire', use a large duration (e.g. math.MaxInt64 nanoseconds) or 0 default, never negative.
- Check subtraction-based duration math for underflow.
- Validate consumer configs before submission in CI.
When it happens
Trigger: ConsumerConfig.InactiveThreshold < 0 passed on consumer create/update with pedantic validation, e.g. InactiveThreshold: -time.Minute or from stream ConsumerLimits-derived values that went negative.
Common situations: Duration subtraction (lastSeen - now) underflow; '-1 = never delete' misconception (use a very large duration instead); templated configs with negative defaults.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- got corrupted escaped character
- max_ack_pending must be set to -1
- max_batch must not be negative
- max_expires must not be negative
- max_bytes must not be negative
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/78d0c8dd70a04312.
Report an issue: GitHub.