nats-io/nats-server · error · ApiError
max_ack_pending must be set if it's configured in stream lim
Error message
max_ack_pending must be set if it's configured in stream limits
What it means
A JetStream pedantic validation error thrown when the stream's ConsumerLimits define a MaxAckPending > 0 but the consumer config leaves MaxAckPending unset (0). Because 0 would otherwise inherit a value exceeding the stream's limit, pedantic mode requires the consumer to state it explicitly at server/consumer.go:686.
Source
Thrown at server/consumer.go:686
// 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
}
// If BackOff was specified that will override the AckWait and the MaxDeliver.
if len(config.BackOff) > 0 {
if pedantic && config.AckWait != config.BackOff[0] {
return NewJSPedanticError(errors.New("first backoff value has to equal batch AckWait"))
}
config.AckWait = config.BackOff[0]
}
if config.MaxAckPending == 0 {
if pedantic && streamCfg.ConsumerLimits.MaxAckPending > 0 {
return NewJSPedanticError(errors.New("max_ack_pending must be set if it's configured in stream limits"))
}
config.MaxAckPending = streamCfg.ConsumerLimits.MaxAckPending
}
if config.InactiveThreshold == 0 {
if pedantic && streamCfg.ConsumerLimits.InactiveThreshold > 0 {
return NewJSPedanticError(errors.New("inactive_threshold must be set if it's configured in stream limits"))
}
config.InactiveThreshold = streamCfg.ConsumerLimits.InactiveThreshold
}
// Set proper default for max ack pending if we are ack explicit and none has been set.
if config.MaxAckPending == 0 && config.AckPolicy != AckNone {
ackPending := JsDefaultMaxAckPending
if lim.MaxAckPending > 0 && lim.MaxAckPending < ackPending {
ackPending = lim.MaxAckPending
}
if accLim.MaxAckPending > 0 && accLim.MaxAckPending < ackPending {
ackPending = accLim.MaxAckPending
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Set MaxAckPending explicitly in the consumer config to a value <= the stream's ConsumerLimits.MaxAckPending.
- Read the stream info first and mirror its ConsumerLimits.MaxAckPending into the consumer config.
- Relax the stream's ConsumerLimits.MaxAckPending to 0 if the cap is no longer needed.
- Update consumer-creation templates to always set MaxAckPending when streams enforce limits.
Example fix
// before
si, _ := js.StreamInfo("ORDERS")
cc := nats.ConsumerConfig{Durable: "w"} // MaxAckPending unset
js.AddConsumer("ORDERS", &cc)
// after
cc := nats.ConsumerConfig{
Durable: "w",
MaxAckPending: si.Config.ConsumerLimits.MaxAckPending,
}
js.AddConsumer("ORDERS", &cc) Defensive patterns
Strategy: validation
Validate before calling
si, err := js.StreamInfo(stream)
if err != nil { return err }
if lim := si.Config.ConsumerLimits.MaxAckPending; lim > 0 && cc.MaxAckPending == 0 {
cc.MaxAckPending = lim
} Try / catch
if _, err := js.AddConsumer(stream, &cc); err != nil && strings.Contains(err.Error(), "max_ack_pending must be set") {
si, _ := js.StreamInfo(stream)
cc.MaxAckPending = si.Config.ConsumerLimits.MaxAckPending
_, err = js.AddConsumer(stream, &cc)
} Prevention
- Fetch stream info and honor ConsumerLimits when creating consumers.
- After adding ConsumerLimits to streams, audit all consumer-creation templates.
- Always set MaxAckPending explicitly rather than relying on defaults.
When it happens
Trigger: Creating/updating a consumer on a stream whose ConsumerLimits.MaxAckPending > 0 while ConsumerConfig.MaxAckPending == 0 with pedantic validation enabled, e.g. stream created with MaxConsumers limits after a server upgrade that introduced ConsumerLimits.
Common situations: After upgrading the server and adding ConsumerLimits to existing streams, previously working consumer templates (which relied on defaults) start failing; multi-tenant setups where admins cap consumers but client code creates consumers without setting the field.
Related errors
- inactive_threshold must be set if it's configured in stream
- got corrupted escaped character
- max_ack_pending must be set to -1
- max_batch must not be negative
- max_expires must not be negative
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/df42aadc9503bac6.
Report an issue: GitHub.