{"record":{"id":"0017413745f360ff","repo":"nats-io/nats-server","slug":"max-msgs-per-subject-must-be-set-to-1","errorCode":null,"errorMessage":"max_msgs_per_subject must be set to -1","messagePattern":"max_msgs_per_subject must be set to -1","errorType":"error_code","errorClass":"JSPedanticError","httpStatus":null,"severity":"error","filePath":"server/stream.go","lineNumber":1928,"sourceCode":"\n\tif cfg.Replicas == 0 {\n\t\tcfg.Replicas = 1\n\t}\n\tif cfg.Replicas > StreamMaxReplicas {\n\t\treturn cfg, NewJSStreamInvalidConfigError(fmt.Errorf(\"maximum replicas is %d\", StreamMaxReplicas))\n\t}\n\tif cfg.Replicas < 0 {\n\t\treturn cfg, NewJSReplicasCountCannotBeNegativeError()\n\t}\n\tif cfg.MaxMsgs == 0 || cfg.MaxMsgs < -1 {\n\t\tif pedantic && cfg.MaxMsgs < -1 {\n\t\t\treturn StreamConfig{}, NewJSPedanticError(fmt.Errorf(\"max_msgs must be set to -1\"))\n\t\t}\n\t\tcfg.MaxMsgs = -1\n\t}\n\tif cfg.MaxMsgsPer == 0 || cfg.MaxMsgsPer < -1 {\n\t\tif pedantic && cfg.MaxMsgsPer < -1 {\n\t\t\treturn StreamConfig{}, NewJSPedanticError(fmt.Errorf(\"max_msgs_per_subject must be set to -1\"))\n\t\t}\n\t\tcfg.MaxMsgsPer = -1\n\t}\n\tif cfg.MaxBytes == 0 || cfg.MaxBytes < -1 {\n\t\tif pedantic && cfg.MaxBytes < -1 {\n\t\t\treturn StreamConfig{}, NewJSPedanticError(fmt.Errorf(\"max_bytes must be set to -1\"))\n\t\t}\n\t\tcfg.MaxBytes = -1\n\t}\n\tif cfg.MaxMsgSize == 0 || cfg.MaxMsgSize < -1 {\n\t\tif pedantic && cfg.MaxMsgSize < -1 {\n\t\t\treturn StreamConfig{}, NewJSPedanticError(fmt.Errorf(\"max_msg_size must be set to -1\"))\n\t\t}\n\t\tcfg.MaxMsgSize = -1\n\t}\n\tif cfg.MaxConsumers == 0 || cfg.MaxConsumers < -1 {\n\t\tif pedantic && cfg.MaxConsumers < -1 {\n\t\t\treturn StreamConfig{}, NewJSPedanticError(fmt.Errorf(\"max_consumers must be set to -1\"))","sourceCodeStart":1910,"sourceCodeEnd":1946,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/stream.go#L1910-L1946","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nStreamConfig{Name: \"ORDERS\", MaxMsgsPer: 0}\n// after\nStreamConfig{Name: \"ORDERS\", MaxMsgsPer: -1}","handlingStrategy":"validation","validationCode":"if cfg.MaxMsgsPer == 0 || cfg.MaxMsgsPer < -1 {\n    return fmt.Errorf(\"MaxMsgsPer must be -1 (unlimited) or positive; got %d\", cfg.MaxMsgsPer)\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    var apiErr *nats.APIError\n    if errors.As(err, &apiErr) && apiErr.ErrorCode == nats.ErrorCodeJetStreamInvalidStreamConfig {\n        cfg.MaxMsgsPer = -1\n        err = createStream(cfg)\n    }\n}","preventionTips":["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"],"tags":["jetstream","stream-config","pedantic","validation"],"backgroundTag":"jetstream-invalid-stream-config","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}