{"record":{"id":"78d0c8dd70a04312","repo":"nats-io/nats-server","slug":"inactive-threshold-must-not-be-negative","errorCode":null,"errorMessage":"inactive_threshold must not be negative","messagePattern":"inactive_threshold must not be negative","errorType":"validation","errorClass":"ApiError","httpStatus":null,"severity":"error","filePath":"server/consumer.go","lineNumber":658,"sourceCode":"\t\t\treturn NewJSPedanticError(errors.New(\"max_expires must not be negative\"))\n\t\t}\n\t\tconfig.MaxRequestExpires = 0\n\t}\n\tif config.MaxRequestMaxBytes < 0 {\n\t\tif pedantic {\n\t\t\treturn NewJSPedanticError(errors.New(\"max_bytes must not be negative\"))\n\t\t}\n\t\tconfig.MaxRequestMaxBytes = 0\n\t}\n\tif config.Heartbeat < 0 {\n\t\tif pedantic {\n\t\t\treturn NewJSPedanticError(errors.New(\"idle_heartbeat must not be negative\"))\n\t\t}\n\t\tconfig.Heartbeat = 0\n\t}\n\tif config.InactiveThreshold < 0 {\n\t\tif pedantic {\n\t\t\treturn NewJSPedanticError(errors.New(\"inactive_threshold must not be negative\"))\n\t\t}\n\t\tconfig.InactiveThreshold = 0\n\t}\n\tif config.PinnedTTL < 0 {\n\t\tif pedantic {\n\t\t\treturn NewJSPedanticError(errors.New(\"priority_timeout must not be negative\"))\n\t\t}\n\t\tconfig.PinnedTTL = 0\n\t}\n\n\t// Set to default if not specified.\n\tif config.DeliverSubject == _EMPTY_ && config.MaxWaiting == 0 {\n\t\tconfig.MaxWaiting = JSWaitQueueDefaultMax\n\t}\n\t// Setup proper default for ack wait if we are in explicit ack mode.\n\tif config.AckWait == 0 && (config.AckPolicy == AckExplicit || config.AckPolicy == AckAll) {\n\t\tconfig.AckWait = JsAckWaitDefault\n\t}","sourceCodeStart":640,"sourceCodeEnd":676,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/consumer.go#L640-L676","documentation":"A JetStream pedantic validation error thrown when InactiveThreshold (the time after which an inactive ephemeral consumer is deleted) is negative. It must be 0 (use default) or a positive duration; pedantic mode rejects the config instead of clamping to 0 at server/consumer.go:658.","triggerScenarios":"ConsumerConfig.InactiveThreshold < 0 passed on consumer create/update with pedantic validation, e.g. InactiveThreshold: -time.Minute or from stream ConsumerLimits-derived values that went negative.","commonSituations":"Duration subtraction (lastSeen - now) underflow; '-1 = never delete' misconception (use a very large duration instead); templated configs with negative defaults.","solutions":["Set InactiveThreshold to 0 for the default or a positive duration (e.g. 5 * time.Minute).","Clamp computed durations to >= 0 before assignment.","If 'never expire' is intended, use a very large duration instead of a negative one.","Validate the config client-side with Validate(true)."],"exampleFix":"// before\ncc := nats.ConsumerConfig{InactiveThreshold: -1 * time.Minute}\n// after\ncc := nats.ConsumerConfig{InactiveThreshold: 5 * time.Minute}","handlingStrategy":"validation","validationCode":"if cfg.InactiveThreshold < 0 { return errors.New(\"inactive_threshold must not be negative\") }","typeGuard":null,"tryCatchPattern":"if _, err := js.AddConsumer(stream, &cc); err != nil && strings.Contains(err.Error(), \"inactive_threshold must not be negative\") {\n    cc.InactiveThreshold = 0\n    _, err = js.AddConsumer(stream, &cc)\n}","preventionTips":["For 'never expire', use a large duration (e.g. math.MaxInt64 nanoseconds) or 0 default, never negative.","Check subtraction-based duration math for underflow.","Validate consumer configs before submission in CI."],"tags":["jetstream","consumer-config","validation","ephemeral-consumer"],"backgroundTag":"invalid-argument-value","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}