{"record":{"id":"70c5b09d79a6ffdf","repo":"mastra-ai/mastra","slug":"heartbeatms-must-be-a-finite-number-no-greater-tha","errorCode":null,"errorMessage":"heartbeatMs must be a finite number no greater than ${MAX_TIMEOUT_MS}","messagePattern":"heartbeatMs must be a finite number no greater than (.+?)","errorType":"validation","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"client-sdks/ai-sdk/src/sse-heartbeat.ts","lineNumber":15,"sourceCode":"const SSE_HEARTBEAT_BYTES = new TextEncoder().encode(': heartbeat\\n\\n');\nconst LF_BYTE = 10;\nconst MAX_TIMEOUT_MS = 2_147_483_647;\n\ntype StreamReadResult<T> = { done: false; value: T } | { done: true; value?: undefined };\ntype WakeReason = 'read' | 'heartbeat';\n\n/** Throws when an enabled heartbeat interval cannot be scheduled with a timer. */\nexport function assertValidHeartbeatMs(heartbeatMs?: number): void {\n  if (\n    heartbeatMs !== undefined &&\n    !(heartbeatMs <= 0) &&\n    (!Number.isFinite(heartbeatMs) || heartbeatMs > MAX_TIMEOUT_MS)\n  ) {\n    throw new RangeError(`heartbeatMs must be a finite number no greater than ${MAX_TIMEOUT_MS}`);\n  }\n}\n\n/**\n * Wraps an SSE `Response` so it emits periodic `: heartbeat` comments while the source is idle,\n * keeping connections alive through proxies that close idle streams.\n *\n * Heartbeats are only inserted between complete SSE frames. AI SDK serialization uses LF-delimited\n * frames, which this wrapper preserves and relies on.\n *\n * Returns the input response unchanged when `heartbeatMs` is omitted, is `<= 0`, or the response has\n * no body. Throws a `RangeError` when `heartbeatMs` is enabled but cannot be scheduled with a timer.\n */\nexport function withSseHeartbeat(response: Response, heartbeatMs?: number): Response {\n  assertValidHeartbeatMs(heartbeatMs);\n  if (heartbeatMs === undefined || heartbeatMs <= 0 || !response.body) {\n    return response;\n  }","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/client-sdks/ai-sdk/src/sse-heartbeat.ts#L1-L33","documentation":"assertValidHeartbeatMs validates the heartbeatMs option used to add periodic SSE ': heartbeat' comments to server-sent-event streams. The interval must be undefined, <= 0 (disabling), or a finite number not exceeding MAX_TIMEOUT_MS; anything else throws this RangeError.","triggerScenarios":"Passing heartbeatMs: Infinity, NaN, or a value larger than MAX_TIMEOUT_MS to chatRoute or withSseHeartbeat; computing an interval from config math that yields NaN or Infinity (e.g. division by a zero/falsy variable).","commonSituations":"Env-var config parsed with Number() returning NaN; a misconfigured 'unlimited' sentinel like Number.MAX_SAFE_INTEGER or Infinity; unit mismatch (milliseconds vs seconds) producing an out-of-range value.","solutions":["Pass a finite positive heartbeatMs within MAX_TIMEOUT_MS (e.g. 15000 for 15 seconds).","Pass 0 or a negative number explicitly to disable heartbeats, or omit the option.","Guard config parsing: Number.isFinite(Number(env.HEARTBEAT_MS)) before use.","Log/computed the value at startup to catch NaN/Infinity from bad math."],"exampleFix":"// before\nconst heartbeatMs = Number(process.env.SSE_HEARTBEAT_MS) || Infinity;\nwithSseHeartbeat(response, { heartbeatMs });\n// after\nconst parsed = Number(process.env.SSE_HEARTBEAT_MS);\nconst heartbeatMs = Number.isFinite(parsed) && parsed > 0 ? parsed : 15000;\nwithSseHeartbeat(response, { heartbeatMs });","handlingStrategy":"validation","validationCode":"function isUsableHeartbeatMs(v: unknown): v is number {\n  return typeof v === 'number' && Number.isFinite(v) && (v <= 0 || v <= 2147483647);\n}","typeGuard":"function isValidHeartbeatMs(v: number | undefined): boolean {\n  return v === undefined || (Number.isFinite(v) && (v <= 0 || v <= MAX_TIMEOUT_MS));\n}","tryCatchPattern":"try {\n  withSseHeartbeat(res, { heartbeatMs });\n} catch (e) {\n  if (e instanceof RangeError && e.message.startsWith('heartbeatMs')) {\n    withSseHeartbeat(res, { heartbeatMs: 15000 });\n  } else throw e;\n}","preventionTips":["Validate env vars with Number.isFinite before assigning numeric config.","Never use Infinity/NaN as a 'default' sentinel for timeouts.","Clamp computed intervals to MAX_TIMEOUT_MS."],"tags":["sse","configuration","range-error","validation"],"backgroundTag":"invalid-option-value","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}