nats-io/nats-server · error · JSStreamUpdateError
10069
10069
Error message
change to limits violates consumers: %s
What it means
JSStreamUpdateError (API error 10069) with message 'change to limits violates consumers: %s' is returned by the stream UPDATE handler when a proposed change to stream limits (max inactive threshold semantics / new MaxAckPending limits being tightened) would make existing consumers of that stream invalid. The comma-joined consumer names listed in the message are the consumers that would violate the new limits.
Source
Thrown at server/jetstream_cluster.go:10324
// In the event that some of the stream-level limits have changed, yell appropriately
// if any of the consumers exceed that limit.
oldInactiveThreshold, newInactiveThreshold := osa.Config.ConsumerLimits.InactiveThreshold, newCfg.ConsumerLimits.InactiveThreshold
oldMaxAckPending, newMaxAckPending := osa.Config.ConsumerLimits.MaxAckPending, newCfg.ConsumerLimits.MaxAckPending
updateLimits := (newInactiveThreshold > 0 && oldInactiveThreshold != newInactiveThreshold) ||
(newMaxAckPending > 0 && oldMaxAckPending != newMaxAckPending)
if updateLimits {
var errorConsumers []string
for ca := range js.consumerAssignmentsOrInflightSeq(acc.Name, newCfg.Name) {
if ca.Config == nil {
continue
}
if (newInactiveThreshold > 0 && ca.Config.InactiveThreshold > newInactiveThreshold) ||
(newMaxAckPending > 0 && ca.Config.MaxAckPending > newMaxAckPending) {
errorConsumers = append(errorConsumers, ca.Name)
}
}
if len(errorConsumers) > 0 {
err := fmt.Errorf("change to limits violates consumers: %s", strings.Join(errorConsumers, ", "))
resp.Error = NewJSStreamUpdateError(err)
s.sendAPIErrResponse(ci, acc, subject, reply, string(rmsg), s.jsonResponse(&resp))
return
}
}
// Check for a move request.
var isMoveRequest bool
if lPeerSet := len(peerSet); lPeerSet > 0 {
isMoveRequest = true
} else {
isMoveRequest = newCfg.Placement != nil && !reflect.DeepEqual(osa.Config.Placement, newCfg.Placement)
}
// Check for replica changes.
isReplicaChange := newCfg.Replicas != osa.Config.Replicas
// Combining a move and a scale in a single update is not allowed.View on GitHub (pinned to 3a66a489d2)
Solutions
- Update or delete the consumers named in the message so they comply with the new limits first.
- Apply the stream limits change after adjusting consumer MaxAckPending/InactiveThreshold values.
- If the change is not essential, keep the current limits and only tighten limits on new consumers.
Example fix
// before: tighten stream limits while consumer exceeds them
js.UpdateStream(nc, streamName, StreamConfig{MaxAckPending: 100})
// after: fix consumers first
for _, c := range violatingConsumers {
cc.MaxAckPending = 100
js.UpdateConsumer(nc, streamName, cc)
}
js.UpdateStream(nc, streamName, StreamConfig{MaxAckPending: 100}) Defensive patterns
Strategy: validation
Validate before calling
// before updating stream limits, check consumers comply
for _, cc := range existingConsumers {
if newMaxAckPending > 0 && cc.MaxAckPending > newMaxAckPending {
// update consumer first
}
if newInactiveThreshold > 0 && cc.InactiveThreshold > newInactiveThreshold {
// update consumer first
}
} Try / catch
_, err := js.UpdateStream(nc, cfg)
var apiErr *nats.APIError
if errors.As(err, &apiErr) && apiErr.ErrorCode == 10069 {
// parse violating consumer names from err, fix them, retry
} Prevention
- List consumers of a stream before tightening its limits.
- Update consumers to comply before applying stream limit changes.
- Test limit changes on staging streams with identical consumers.
- Automate consumer audits after any stream config change.
When it happens
Trigger: Issuing `$JS.API.STREAM.UPDATE.*` (or `js.UpdateStream`) where the new config tightens limits (e.g. lower max ack pending / inactive threshold bounds) while one or more existing consumers currently exceed those limits.
Common situations: Downsizing a stream's limits in production while long-lived consumers are attached; automation that copies a template config onto streams with pre-existing consumers.
Related errors
- 10052
- 10052
- 10094
- max_request_batch must be set if it's JetStream limits are s
- consumer name can not contain '.', '*', '>', '\', '/'
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/0ed059216c0780ff.
Report an issue: GitHub.