{"record":{"id":"96848eb4136805c9","repo":"nsqio/nsq","slug":"e-bad-body","errorCode":"E_BAD_BODY","errorMessage":"heartbeat interval (%d) is invalid","messagePattern":"heartbeat interval \\((.+?)\\) is invalid","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nsqd/client_v2.go","lineNumber":514,"sourceCode":"\nfunc (c *clientV2) UnPause() {\n\tc.tryUpdateReadyState()\n}\n\nfunc (c *clientV2) SetHeartbeatInterval(desiredInterval int) error {\n\tc.writeLock.Lock()\n\tdefer c.writeLock.Unlock()\n\n\tswitch {\n\tcase desiredInterval == -1:\n\t\tc.HeartbeatInterval = 0\n\tcase desiredInterval == 0:\n\t\t// do nothing (use default)\n\tcase desiredInterval >= 1000 &&\n\t\tdesiredInterval <= int(c.nsqd.getOpts().MaxHeartbeatInterval/time.Millisecond):\n\t\tc.HeartbeatInterval = time.Duration(desiredInterval) * time.Millisecond\n\tdefault:\n\t\treturn fmt.Errorf(\"heartbeat interval (%d) is invalid\", desiredInterval)\n\t}\n\n\treturn nil\n}\n\nfunc (c *clientV2) SetOutputBuffer(desiredSize int, desiredTimeout int) error {\n\tc.writeLock.Lock()\n\tdefer c.writeLock.Unlock()\n\n\tswitch {\n\tcase desiredTimeout == -1:\n\t\tc.OutputBufferTimeout = 0\n\tcase desiredTimeout == 0:\n\t\t// do nothing (use default)\n\tcase true &&\n\t\tdesiredTimeout >= int(c.nsqd.getOpts().MinOutputBufferTimeout/time.Millisecond) &&\n\t\tdesiredTimeout <= int(c.nsqd.getOpts().MaxOutputBufferTimeout/time.Millisecond):\n","sourceCodeStart":496,"sourceCodeEnd":532,"githubUrl":"https://github.com/nsqio/nsq/blob/85cf10c09c6c3c86160d6f0eb156f62d0efc1648/nsqd/client_v2.go#L496-L532","documentation":"During IDENTIFY negotiation, a client may ask for a custom heartbeat interval. clientV2.SetHeartbeatInterval accepts -1 (disable heartbeats), 0 (keep the nsqd default), or any millisecond value from 1000 up to --max-heartbeat-interval (default 60000ms). Anything else returns this error, which surfaces to the client as E_BAD_BODY, and the connection's IDENTIFY fails.","triggerScenarios":"Sending heartbeat: 500 (below the 1s floor), heartbeat: -5 (only exactly -1 is special), heartbeat: 120000 when max is 60s, or passing microseconds/seconds where milliseconds are expected (unit confusion is the classic case).","commonSituations":"Porting a client from another broker whose heartbeat unit is seconds (e.g. sending 30 meaning 30s, which passes validation but means 30ms of the wrong scale, or sending 90000 for 90s and tripping the max); tuning liveness for long-idle consumers above the server max.","solutions":["Send a value in the accepted window: 1000 <= v <= 60000 (milliseconds), or 0 for the server default, or -1 to disable","If you genuinely need intervals above 60s, raise --max-heartbeat-interval on nsqd","Double-check the unit: the field is milliseconds, not seconds or microseconds","Re-check your client library's IDENTIFY struct after upgrades that changed field semantics"],"exampleFix":"// go-nsq consumer config\n// before\ncfg.HeartbeatInterval = 90 * time.Second // sent as 90000ms > 60s max -> E_BAD_BODY\n\n// after\ncfg.HeartbeatInterval = 30 * time.Second // 30000ms, within [1000,60000]","handlingStrategy":"validation","validationCode":"func clampHeartbeat(ms int, maxMs int) int {\n\tswitch {\n\tcase ms == -1 || ms == 0:\n\t\treturn ms\n\tcase ms < 1000:\n\t\treturn 0 // fall back to server default\n\tcase ms > maxMs:\n\t\treturn maxMs\n\t}\n\treturn ms\n}","typeGuard":null,"tryCatchPattern":"// client libraries surface this as an IDENTIFY error on connect:\n// catch the connect/identify error, log the exact heartbeat value, fix and reconnect","preventionTips":["Configure heartbeats through the client library's Duration field, not raw ints","Confirm the server's --max-heartbeat-interval before raising client values","Unit-test client IDENTIFY payloads against the documented [1000, max] window"],"tags":["nsqd","protocol","identify","heartbeat","validation"],"backgroundTag":null,"analyzedSha":"85cf10c09c6c3c86160d6f0eb156f62d0efc1648","analyzedAt":"2026-08-16T00:53:05.009Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}