{"record":{"id":"c800d199c4266df6","repo":"danny-avila/LibreChat","slug":"path-contains-a-non-json-typeof-value-value","errorCode":null,"errorMessage":"${path} contains a non-JSON ${typeof value} value","messagePattern":"(.+?) contains a non-JSON (.+?) value","errorType":"validation","errorClass":"AgentRunEnvelopeError","httpStatus":null,"severity":"error","filePath":"packages/api/src/agents/envelope.ts","lineNumber":119,"sourceCode":"  if (depth > AGENT_RUN_ENVELOPE_MAX_NESTING_DEPTH) {\n    throw new AgentRunEnvelopeError(\n      `${path} exceeds the maximum nesting depth of ${AGENT_RUN_ENVELOPE_MAX_NESTING_DEPTH}`,\n    );\n  }\n\n  if (value === null || typeof value === 'string' || typeof value === 'boolean') {\n    return value;\n  }\n\n  if (typeof value === 'number') {\n    if (!Number.isFinite(value)) {\n      throw new AgentRunEnvelopeError(`${path} must contain only finite numbers`);\n    }\n    return value;\n  }\n\n  if (typeof value !== 'object') {\n    throw new AgentRunEnvelopeError(`${path} contains a non-JSON ${typeof value} value`);\n  }\n\n  if (ancestors.has(value)) {\n    throw new AgentRunEnvelopeError(`${path} contains a circular reference`);\n  }\n\n  ancestors.add(value);\n\n  try {\n    const symbolKeys = Object.getOwnPropertySymbols(value);\n    if (symbolKeys.length > 0) {\n      throw new AgentRunEnvelopeError(`${path} contains symbol keys`);\n    }\n\n    if (Array.isArray(value)) {\n      const cloned: unknown[] = new Array(value.length);\n      let clonedItemCount = 0;\n      for (const key of Object.getOwnPropertyNames(value)) {","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/packages/api/src/agents/envelope.ts#L101-L137","documentation":"Thrown by cloneJsonValue inside createAgentRunEnvelope when a value anywhere in the agent-run payload has a non-JSON typeof ('undefined', 'function', 'bigint', or 'symbol'). The envelope must cross the execution seam as pure JSON, so any value JSON.stringify would drop or reject is refused here. This guard exists because a leaked function/closure can pull runtime state (DB clients, credentials, Express req) into the sandbox payload.","triggerScenarios":"A payload field set to undefined, a function reference, a BigInt (e.g. 123n), or a Symbol value. Common: an extension field left undefined; a callback accidentally attached to the request object; a numeric ID parsed as BigInt before being placed in the payload.","commonSituations":"Adding a new AgentRunPayloadExtensions field and forgetting to default it; converting numeric IDs to BigInt for precision and passing them through; copying a provider SDK request object whose prototype carries function-valued options.","solutions":["Inspect the path in the message (e.g. 'payload.messages[2].content') to locate the offending field.","Replace undefined fields with null, strip function references, and convert BigInt to string/number before building the envelope.","Add a pre-flight isPlainJsonValue check (see defense) over the payload before calling createAgentRunEnvelope."],"exampleFix":"// before\nconst payload = { ...req, onCancel: () => abortController.abort() };\nconst env = createAgentRunEnvelope({ protocol: 'chat.completions', requestId, receivedAt, principal, payload });\n\n// after\nconst { onCancel, ...serializable } = req;\nconst payload = { ...serializable, onCancel: null };\nconst env = createAgentRunEnvelope({ protocol: 'chat.completions', requestId, receivedAt, principal, payload });","handlingStrategy":"type-guard","validationCode":"const NON_JSON_TYPES = new Set(['undefined', 'function', 'bigint', 'symbol']);\nfunction hasNonJsonValue(value: unknown, path = 'payload'): string | null {\n  const t = typeof value;\n  if (value === null || t === 'string' || t === 'boolean') return null;\n  if (t === 'number') return Number.isFinite(value) ? null : `${path} must contain only finite numbers`;\n  if (NON_JSON_TYPES.has(t)) return `${path} contains a non-JSON ${t} value`;\n  return null;\n}\n// before building the envelope:\nfor (const [k, v] of Object.entries(payload)) {\n  const err = hasNonJsonValue(v, `payload.${k}`);\n  if (err) throw new Error(err);\n}","typeGuard":"function isJsonScalar(value: unknown): value is string | number | boolean | null {\n  if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;\n  if (typeof value === 'number') return Number.isFinite(value);\n  return false; // undefined, function, bigint, symbol\n}","tryCatchPattern":"try {\n  const env = createAgentRunEnvelope(input);\n} catch (e) {\n  if (e instanceof AgentRunEnvelopeError && /non-JSON/.test(e.message)) {\n    // sanitize payload: drop undefined fields, convert BigInt to String\n  } else throw e;\n}","preventionTips":["Never spread untyped/SDK objects into the payload; pick fields explicitly.","Default optional fields to null rather than leaving them undefined.","Run JSON.parse(JSON.stringify(payload)) in dev/test before calling createAgentRunEnvelope to catch non-JSON values early."],"tags":["serialization","json","agent-envelope","type-error","payload-validation"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}