{"record":{"id":"94c3130a5e6a6e84","repo":"nats-io/nats-server","slug":"invalid-retention","errorCode":null,"errorMessage":"invalid retention","messagePattern":"invalid retention","errorType":"error_code","errorClass":"JSStreamInvalidConfigError","httpStatus":null,"severity":"error","filePath":"server/stream.go","lineNumber":1894,"sourceCode":"\tif len(config.Name) > JSMaxNameLen {\n\t\treturn StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf(\"stream name is too long, maximum allowed is %d\", JSMaxNameLen))\n\t}\n\tif len(config.Description) > JSMaxDescriptionLen {\n\t\treturn StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf(\"stream description is too long, maximum allowed is %d\", JSMaxDescriptionLen))\n\t}\n\n\tvar metadataLen int\n\tfor k, v := range config.Metadata {\n\t\tmetadataLen += len(k) + len(v)\n\t}\n\tif metadataLen > JSMaxMetadataLen {\n\t\treturn StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf(\"stream metadata exceeds maximum size of %d bytes\", JSMaxMetadataLen))\n\t}\n\n\tcfg := *config\n\n\tif _, err := cfg.Retention.MarshalJSON(); err != nil {\n\t\treturn cfg, NewJSStreamInvalidConfigError(fmt.Errorf(\"invalid retention\"))\n\t}\n\tif _, err := cfg.Discard.MarshalJSON(); err != nil {\n\t\treturn cfg, NewJSStreamInvalidConfigError(fmt.Errorf(\"invalid discard policy\"))\n\t}\n\tif _, err := cfg.Compression.MarshalJSON(); err != nil {\n\t\treturn cfg, NewJSStreamInvalidConfigError(fmt.Errorf(\"invalid compression\"))\n\t}\n\n\t// Make file the default.\n\tif cfg.Storage == 0 {\n\t\tcfg.Storage = FileStorage\n\t}\n\tif _, err := cfg.Storage.MarshalJSON(); err != nil {\n\t\treturn cfg, NewJSStreamInvalidConfigError(fmt.Errorf(\"invalid storage type\"))\n\t}\n\n\tif cfg.Replicas == 0 {\n\t\tcfg.Replicas = 1","sourceCodeStart":1876,"sourceCodeEnd":1912,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/stream.go#L1876-L1912","documentation":"cfg.Retention (a RetentionPolicy enum) failed to marshal to JSON inside checkStreamCfgLocked, meaning it holds a value outside the known retention policies (Limits, Interest, WorkQueue). The config is rejected as 'invalid retention'.","triggerScenarios":"Passing an out-of-range integer cast to RetentionPolicy, a zero-value from an uninitialized struct where the enum does not include 0, or a retention value decoded from a config file that doesn't match any valid policy.","commonSituations":"Hand-writing JSON like \"retention\": \"limit\" (string instead of numeric enum) sent directly to the API; copy-pasting RetentionPolicy values across client library versions; Go clients constructing StreamConfig{Retention: RetentionPolicy(7)}.","solutions":["Set Retention to one of jetstream.LimitsPolicy, InterestPolicy, or WorkQueuePolicy.","If sending raw JSON, omit 'retention' to use the default (Limits) or use the numeric enum value the server expects.","Validate the enum value before building the config.","Check client/server version skew for enum value mismatches."],"exampleFix":"// before\ncfg := jetstream.StreamConfig{Name: \"ORDERS\", Retention: jetstream.RetentionPolicy(7)}\n// after\ncfg := jetstream.StreamConfig{Name: \"ORDERS\", Retention: jetstream.WorkQueuePolicy}","handlingStrategy":"validation","validationCode":"func validRetention(r jetstream.RetentionPolicy) error {\n  switch r {\n  case jetstream.LimitsPolicy, jetstream.InterestPolicy, jetstream.WorkQueuePolicy:\n    return nil\n  }\n  return fmt.Errorf(\"invalid retention policy: %d\", int(r))\n}","typeGuard":"func isKnownRetention(r jetstream.RetentionPolicy) bool {\n  return r == jetstream.LimitsPolicy || r == jetstream.InterestPolicy || r == jetstream.WorkQueuePolicy\n}","tryCatchPattern":null,"preventionTips":["Always set Retention from named constants, never integer casts.","Omit the field to accept the default Limits policy.","Validate enum values when decoding configs from files/JSON.","Watch for version skew between client enum values and server."],"tags":["jetstream","stream-config","retention-policy","enum"],"backgroundTag":"invalid-retention-policy","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}