nats-io/nats-server · error · JSPedanticError
max_msgs_per_subject must be set to -1
Error message
max_msgs_per_subject must be set to -1
What it means
Pedantic-mode validation for MaxMsgsPer (per-subject message limit): values of 0 or < -1 are rejected with a JSPedanticError instead of being silently normalized to -1 (unlimited). Only exactly -1 or a positive number is accepted.
Source
Thrown at server/stream.go:1928
if cfg.Replicas == 0 {
cfg.Replicas = 1
}
if cfg.Replicas > StreamMaxReplicas {
return cfg, NewJSStreamInvalidConfigError(fmt.Errorf("maximum replicas is %d", StreamMaxReplicas))
}
if cfg.Replicas < 0 {
return cfg, NewJSReplicasCountCannotBeNegativeError()
}
if cfg.MaxMsgs == 0 || cfg.MaxMsgs < -1 {
if pedantic && cfg.MaxMsgs < -1 {
return StreamConfig{}, NewJSPedanticError(fmt.Errorf("max_msgs must be set to -1"))
}
cfg.MaxMsgs = -1
}
if cfg.MaxMsgsPer == 0 || cfg.MaxMsgsPer < -1 {
if pedantic && cfg.MaxMsgsPer < -1 {
return StreamConfig{}, NewJSPedanticError(fmt.Errorf("max_msgs_per_subject must be set to -1"))
}
cfg.MaxMsgsPer = -1
}
if cfg.MaxBytes == 0 || cfg.MaxBytes < -1 {
if pedantic && cfg.MaxBytes < -1 {
return StreamConfig{}, NewJSPedanticError(fmt.Errorf("max_bytes must be set to -1"))
}
cfg.MaxBytes = -1
}
if cfg.MaxMsgSize == 0 || cfg.MaxMsgSize < -1 {
if pedantic && cfg.MaxMsgSize < -1 {
return StreamConfig{}, NewJSPedanticError(fmt.Errorf("max_msg_size must be set to -1"))
}
cfg.MaxMsgSize = -1
}
if cfg.MaxConsumers == 0 || cfg.MaxConsumers < -1 {
if pedantic && cfg.MaxConsumers < -1 {
return StreamConfig{}, NewJSPedanticError(fmt.Errorf("max_consumers must be set to -1"))View on GitHub (pinned to 3a66a489d2)
Solutions
- Set MaxMsgsPer to -1 explicitly for unlimited per-subject messages
- Set a positive integer per-subject limit
- Turn off pedantic validation if silent normalization to -1 is acceptable
Example fix
// before
StreamConfig{Name: "ORDERS", MaxMsgsPer: 0}
// after
StreamConfig{Name: "ORDERS", MaxMsgsPer: -1} Defensive patterns
Strategy: validation
Validate before calling
if cfg.MaxMsgsPer == 0 || cfg.MaxMsgsPer < -1 {
return fmt.Errorf("MaxMsgsPer must be -1 (unlimited) or positive; got %d", cfg.MaxMsgsPer)
} Try / catch
if err != nil {
var apiErr *nats.APIError
if errors.As(err, &apiErr) && apiErr.ErrorCode == nats.ErrorCodeJetStreamInvalidStreamConfig {
cfg.MaxMsgsPer = -1
err = createStream(cfg)
}
} Prevention
- Sanitize sentinel values from external systems to exactly -1 for unlimited
- Keep a shared config-normalizer that clamps all *Per fields
- Add unit tests covering pedantic mode for per-subject limits
When it happens
Trigger: Stream create/update API call in pedantic mode with MaxMsgsPer=0 or MaxMsgsPer<-1; e.g. a per-subject limit template that computed a negative number. server/stream.go:1928.
Common situations: Apps using per-subject limits (subject-level retention) that leave the field unset; config generators emitting -2/-100 as an 'infinite' sentinel from other systems; newly enabling pedantic mode on an existing template.
Related errors
- max_msgs must be set to -1
- max_bytes must be set to -1
- max_msg_size must be set to -1
- max_consumers must be set to -1
- duplicate window cannot be bigger than max age
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/0017413745f360ff.
Report an issue: GitHub.