{"record":{"id":"8bf036ae4c304855","repo":"vercel/ai","slug":"continuation-maxagems-must-be-a-positive-integer","errorCode":null,"errorMessage":"Continuation maxAgeMs must be a positive integer.","messagePattern":"Continuation maxAgeMs must be a positive integer\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/code-mode/src/continuation-capability.ts","lineNumber":52,"sourceCode":"  options: CodeModeContinuationSecurityOptions = {},\n): ResolvedCodeModeContinuationSecurity {\n  const signingKey =\n    options.signingKey === undefined\n      ? Buffer.from(defaultSigningKey)\n      : typeof options.signingKey === 'string'\n        ? Buffer.from(options.signingKey)\n        : Buffer.from(options.signingKey);\n  if (signingKey.byteLength === 0) {\n    throw new TypeError('Continuation signing key must not be empty.');\n  }\n\n  const maxAgeMs = options.maxAgeMs ?? defaultMaxAgeMs;\n  if (\n    !Number.isInteger(maxAgeMs) ||\n    !Number.isFinite(maxAgeMs) ||\n    maxAgeMs <= 0\n  ) {\n    throw new TypeError('Continuation maxAgeMs must be a positive integer.');\n  }\n\n  return { signingKey, maxAgeMs };\n}\n\nexport function signCodeModeContinuation(\n  continuation: UnsignedCodeModeContinuation,\n  security = resolveCodeModeContinuationSecurity(),\n): CodeModeContinuation {\n  const issuedAtMs = Date.now();\n  const auth: Omit<CodeModeContinuationAuth, 'signature'> = {\n    alg: SIGNATURE_ALGORITHM,\n    nonce: randomBytes(16).toString('hex'),\n    issuedAtMs,\n    expiresAtMs: issuedAtMs + security.maxAgeMs,\n  };\n  return {\n    ...structuredClone(continuation),","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/code-mode/src/continuation-capability.ts#L34-L70","documentation":"resolveCodeModeContinuationSecurity validates the maxAgeMs option and throws a TypeError unless it is a positive, finite integer. maxAgeMs determines how long a signed continuation token remains valid (expiresAtMs = issuedAtMs + maxAgeMs). Values like 0, negative numbers, non-integers, NaN, or Infinity are rejected.","triggerScenarios":"Passing maxAgeMs: 0 or a negative value to setCodeModeContinuationSigningKey or a security options object; passing NaN/Infinity from a bad numeric parse (Number('abc'), Number.POSITIVE_INFINITY); passing a float like 1500.5; passing a value computed as 0 due to a multiplication by an unset config variable.","commonSituations":"Config value parsed with parseInt from an empty string yielding NaN; template-driven config where maxAgeMs is a string that got Number()'d to NaN; a default of 0 used for 'unset'; mistaking seconds for milliseconds and passing sub-1ms fractional values.","solutions":["Pass maxAgeMs as a positive integer in milliseconds, e.g. 60 * 60 * 1000 for 1 hour","If unsure, omit the option to use the library default (1 hour)","Validate the value before passing: Number.isInteger(v) && Number.isFinite(v) && v > 0","Fix the upstream parse producing NaN/0 (e.g. guard Number(config.maxAgeMs) || DEFAULT)"],"exampleFix":"// before\nsetCodeModeContinuationSigningKey(key, { maxAgeMs: Number(process.env.MAX_AGE) }); // NaN\n// after\nconst maxAgeMs = Number.parseInt(process.env.MAX_AGE ?? '', 10);\nsetCodeModeContinuationSigningKey(key, {\n  maxAgeMs: Number.isInteger(maxAgeMs) && maxAgeMs > 0 ? maxAgeMs : 60 * 60 * 1000,\n});","handlingStrategy":"validation","validationCode":"const maxAgeMs = options.maxAgeMs;\nif (maxAgeMs !== undefined && (!Number.isInteger(maxAgeMs) || !Number.isFinite(maxAgeMs) || maxAgeMs <= 0)) {\n  throw new Error(`maxAgeMs must be a positive integer (ms), got: ${String(maxAgeMs)}`);\n}","typeGuard":"function isValidMaxAgeMs(v: unknown): v is number {\n  return typeof v === 'number' && Number.isInteger(v) && Number.isFinite(v) && v > 0;\n}","tryCatchPattern":"try {\n  resolveCodeModeContinuationSecurity({ signingKey: key, maxAgeMs });\n} catch (error) {\n  if (error instanceof TypeError && /maxAgeMs/.test(error.message)) {\n    console.error('Bad maxAgeMs value:', maxAgeMs);\n    return resolveCodeModeContinuationSecurity({ signingKey: key }); // use library default\n  }\n  throw error;\n}","preventionTips":["Express durations in milliseconds explicitly (e.g. 60 * 60 * 1000)","Guard Number(...) parses with Number.isInteger before use","Never pass user- or config-supplied numbers without validating positivity and integrality","Omit maxAgeMs to rely on the 1-hour library default"],"tags":["configuration","validation","continuation-token","max-age"],"backgroundTag":"invalid-config-value","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}