{"record":{"id":"797f1e855b34bd9f","repo":"nats-io/nats-server","slug":"invalid-discard-policy","errorCode":null,"errorMessage":"invalid discard policy","messagePattern":"invalid discard policy","errorType":"error_code","errorClass":"JSStreamInvalidConfigError","httpStatus":null,"severity":"error","filePath":"server/stream.go","lineNumber":1897,"sourceCode":"\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\n\t}\n\tif cfg.Replicas > StreamMaxReplicas {\n\t\treturn cfg, NewJSStreamInvalidConfigError(fmt.Errorf(\"maximum replicas is %d\", StreamMaxReplicas))","sourceCodeStart":1879,"sourceCodeEnd":1915,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/stream.go#L1879-L1915","documentation":"checkStreamCfgLocked: the stream's Discard policy failed to marshal/unmarshal as a valid DiscardPolicy enum — the configured discard value is not one of the recognized policies (old/new or limits/new). Surfaced as NewJSStreamInvalidConfigError; the API layer maps it to an invalid stream configuration error.","triggerScenarios":"Passing an invalid cast value like DiscardPolicy(5), an uninitialized enum from an untyped struct, or decoding a config where 'discard' is a string (\"old\") instead of the expected enum in raw API JSON.","commonSituations":"Config templating that interpolates wrong types into the discard field; cross-version enum mismatches; copy-pasted constants from other messaging systems.","solutions":["Set Discard to jetstream.DiscardOld or jetstream.DiscardNew explicitly.","Omit the field to accept the default (DiscardOld).","Validate the enum before submitting; log its numeric value if unsure.","When using raw JSON requests, use the correct numeric enum value."],"exampleFix":"// before\ncfg := jetstream.StreamConfig{Name: \"ORDERS\", Discard: jetstream.DiscardPolicy(5)}\n// after\ncfg := jetstream.StreamConfig{Name: \"ORDERS\", Discard: jetstream.DiscardNew}","handlingStrategy":"validation","validationCode":"func validDiscard(d jetstream.DiscardPolicy) error {\n  switch d {\n  case jetstream.DiscardOld, jetstream.DiscardNew:\n    return nil\n  }\n  return fmt.Errorf(\"invalid discard policy: %d\", int(d))\n}","typeGuard":"func isKnownDiscard(d jetstream.DiscardPolicy) bool {\n  return d == jetstream.DiscardOld || d == jetstream.DiscardNew\n}","tryCatchPattern":null,"preventionTips":["Use only DiscardOld/DiscardNew constants.","Omit Discard to accept the default (DiscardOld).","Validate the field when building configs from untyped data.","Note max-age/discard interplay only matters with valid enum values; validate early."],"tags":["jetstream","stream-config","discard-policy","enum"],"backgroundTag":"invalid-discard-policy","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}