{"record":{"id":"0a28b99dd28d9f55","repo":"nats-io/nats-server","slug":"idle-heartbeat-must-not-be-negative","errorCode":null,"errorMessage":"idle_heartbeat must not be negative","messagePattern":"idle_heartbeat must not be negative","errorType":"validation","errorClass":"ApiError","httpStatus":null,"severity":"error","filePath":"server/consumer.go","lineNumber":652,"sourceCode":"\t\t\treturn NewJSPedanticError(errors.New(\"max_batch must not be negative\"))\n\t\t}\n\t\tconfig.MaxRequestBatch = 0\n\t}\n\tif config.MaxRequestExpires < 0 {\n\t\tif pedantic {\n\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 {","sourceCodeStart":634,"sourceCodeEnd":670,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/consumer.go#L634-L670","documentation":"A JetStream pedantic validation error thrown when the consumer's Heartbeat (idle_heartbeat interval for push/hb consumers) is negative. Heartbeat intervals are durations and must be zero (disabled) or positive; pedantic mode rejects instead of clamping at server/consumer.go:652.","triggerScenarios":"ConsumerConfig.Heartbeat < 0 (e.g. -2 * time.Second) on consumer create/update with pedantic validation; often from a subtracted duration or a '-1 = disabled' misconception.","commonSituations":"Users of other APIs where -1 disables a timer; duration arithmetic underflow; env-parsed intervals like IDLE_HEARTBEAT=-5s; dashboard forms accepting negative inputs.","solutions":["Set Heartbeat to 0 to disable idle heartbeats or a positive duration (e.g. 5 * time.Second).","Clamp parsed/computed durations to >= 0 before assignment.","Reject negative values in your config parsing layer with a clear message.","Validate client-side with Validate(true) before calling the server."],"exampleFix":"// before\nhb := deadline.Sub(now) // may be negative\ncc := nats.ConsumerConfig{Heartbeat: hb}\n// after\nif hb < 0 { hb = 5 * time.Second }\ncc := nats.ConsumerConfig{Heartbeat: hb}","handlingStrategy":"validation","validationCode":"if cfg.Heartbeat < 0 { return errors.New(\"idle_heartbeat must not be negative\") }","typeGuard":null,"tryCatchPattern":"if _, err := js.AddConsumer(stream, &cc); err != nil && strings.Contains(err.Error(), \"idle_heartbeat\") {\n    cc.Heartbeat = 0\n    _, err = js.AddConsumer(stream, &cc)\n}","preventionTips":["Disable heartbeats with 0, not a negative duration.","Guard parsed durations from env/flags against negative values.","Clamp deadline-derived intervals before assigning to Heartbeat."],"tags":["jetstream","consumer-config","validation","heartbeat"],"backgroundTag":"invalid-argument-value","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}