{"record":{"id":"b82db1ddac1f2221","repo":"nats-io/nats-server","slug":"max-consumers-must-be-set-to-1","errorCode":null,"errorMessage":"max_consumers must be set to -1","messagePattern":"max_consumers must be set to -1","errorType":"error_code","errorClass":"JSPedanticError","httpStatus":null,"severity":"error","filePath":"server/stream.go","lineNumber":1946,"sourceCode":"\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\"))\n\t\t}\n\t\tcfg.MaxConsumers = -1\n\t}\n\tif cfg.MaxAge < 0 {\n\t\treturn StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf(\"max age can not be negative\"))\n\t}\n\tif cfg.MaxAge != 0 && cfg.MaxAge < 100*time.Millisecond {\n\t\treturn StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf(\"max age needs to be >= 100ms\"))\n\t}\n\n\tif cfg.Duplicates == 0 && cfg.Mirror == nil && len(cfg.Sources) == 0 {\n\t\tmaxWindow := StreamDefaultDuplicatesWindow\n\t\tif lim.Duplicates > 0 && maxWindow > lim.Duplicates {\n\t\t\tif pedantic {\n\t\t\t\treturn StreamConfig{}, NewJSPedanticError(fmt.Errorf(\"duplicate window limits are higher than current limits\"))\n\t\t\t}\n\t\t\tmaxWindow = lim.Duplicates\n\t\t}","sourceCodeStart":1928,"sourceCodeEnd":1964,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/stream.go#L1928-L1964","documentation":"Pedantic-mode validation for MaxConsumers (consumer count limit): 0 or any value < -1 triggers JSPedanticError; only -1 (unlimited) or a positive count passes. Non-pedantic mode silently sets it to -1.","triggerScenarios":"Stream create/update in pedantic mode with MaxConsumers=0 or MaxConsumers<-1; e.g. a UI that defaults the field to 0 intending 'unlimited'. server/stream.go:1946.","commonSituations":"Streams expected to be attached to many consumers but config left unset; quota tools emitting 0; enabling pedantic mode after server upgrade on existing templates.","solutions":["Set MaxConsumers to -1 for unlimited consumers","Set a positive consumer quota (e.g. 100) if you want to cap consumers","Disable pedantic checks to permit 0 -> -1 coercion"],"exampleFix":"// before\nStreamConfig{Name: \"ORDERS\", MaxConsumers: 0}\n// after\nStreamConfig{Name: \"ORDERS\", MaxConsumers: -1}","handlingStrategy":"validation","validationCode":"if cfg.MaxConsumers == 0 || cfg.MaxConsumers < -1 {\n    return fmt.Errorf(\"MaxConsumers must be -1 (unlimited) or positive; got %d\", cfg.MaxConsumers)\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    var apiErr *nats.APIError\n    if errors.As(err, &apiErr) && apiErr.ErrorCode == nats.ErrorCodeJetStreamInvalidStreamConfig {\n        cfg.MaxConsumers = -1\n        err = createStream(cfg)\n    }\n}","preventionTips":["Set MaxConsumers explicitly in every stream template","Normalize UI defaults to -1 rather than 0 for 'unlimited'","Run pedantic-mode validation in CI to catch these early"],"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"}