{"record":{"id":"671d603480c4cb83","repo":"pydantic/monty","slug":"cannot-convert-js-symbol-to-monty-value","errorCode":null,"errorMessage":"Cannot convert JS Symbol to Monty value","messagePattern":"Cannot convert JS Symbol to Monty value","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"crates/monty-js/ts/worker/value.ts","lineNumber":63,"sourceCode":"  } else if (typeof value === 'string') {\n    node = { tag: 'text', val: value }\n  } else if (value instanceof Uint8Array) {\n    node = { tag: 'bytes', val: value }\n  } else if (Array.isArray(value)) {\n    const items = Uint32Array.from(value.map((item) => pushValue(item, nodes)))\n    node = { tag: isTuple(value) ? 'tuple-value' : 'list-value', val: items }\n  } else if (value instanceof Map) {\n    node = { tag: 'dict', val: pushPairs([...value.entries()], nodes) }\n  } else if (value instanceof Set) {\n    node = { tag: 'set', val: Uint32Array.from([...value].map((item) => pushValue(item, nodes))) }\n  } else if (typeof value === 'function') {\n    node = { tag: 'function', val: { name: value.name ?? '' } }\n  } else if (typeof value === 'object') {\n    const object = value as Record<string, unknown>\n    node =\n      TYPE_MARKER in object ? pushMarked(object, nodes) : { tag: 'dict', val: pushPairs(Object.entries(object), nodes) }\n  } else if (typeof value === 'symbol') {\n    throw new TypeError('Cannot convert JS Symbol to Monty value')\n  } else {\n    throw unsupported(`value of type ${typeof value}`)\n  }\n  const index = nodes.length\n  nodes.push(node)\n  return index\n}\n\n/** Converts a `__monty_type__` marker into one semantic value node. */\nfunction pushMarked(object: Record<string, unknown>, nodes: ValueNode[]): ValueNode {\n  switch (object[TYPE_MARKER]) {\n    case 'Ellipsis':\n      return { tag: 'ellipsis' }\n    case 'NotImplemented':\n      return { tag: 'not-implemented' }\n    case 'Date':\n      return {\n        tag: 'date',","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty-js/ts/worker/value.ts#L45-L81","documentation":"When converting JS inputs into Monty values, JavaScript `Symbol` has no Monty/Python counterpart the converter supports, so it is rejected explicitly with a `TypeError` while building the flat node arena. All other primitives (string, number, boolean, null, undefined, bigint, function) and plain objects/arrays are convertible; Symbols are not.","triggerScenarios":"Passing a Symbol (or an object containing a Symbol property value, e.g. in `inputs` or nested structures) to `feedRun`/`feed` so that `pushValue` walks into it: `inputs: { key: Symbol('x') }`.","commonSituations":"Using well-known Symbols (`Symbol.iterator`, `Symbol.asyncIterator`) or library sentinel Symbols as input values; accidentally forwarding a config object containing Symbol sentinels; serializing structures that use Symbols as private fields.","solutions":["Replace Symbol values with plain strings or another primitive before passing inputs: `String(sym)` won't help — use the symbol's description explicitly (`sym.description ?? ''`).","Strip Symbol-valued properties from input objects (Symbols are also skipped by `JSON.stringify` — mirror that filtering).","Use a dedicated sentinel string or enum value instead of a Symbol to communicate sentinel semantics to the sandboxed Python code."],"exampleFix":"// before\nawait session.feedRun(code, { inputs: { key: Symbol('x') } }) // TypeError\n\n// after\nawait session.feedRun(code, { inputs: { key: 'x' } })","handlingStrategy":"type-guard","validationCode":"function assertConvertible(v: unknown): void {\n  if (typeof v === 'symbol') throw new TypeError('Symbol inputs are not supported')\n  if (v && typeof v === 'object') Object.values(v).forEach(assertConvertible)\n}","typeGuard":"function isConvertible(v: unknown): boolean {\n  if (typeof v === 'symbol') return false\n  if (v && typeof v === 'object') return Object.values(v).every(isConvertible)\n  return true\n}","tryCatchPattern":"try {\n  await session.feedRun(code, { inputs })\n} catch (err) {\n  if (err instanceof TypeError && err.message.includes('Symbol')) {\n    await session.feedRun(code, { inputs: stripSymbols(inputs) })\n  } else throw err\n}","preventionTips":["Strip Symbol-valued properties from inputs before sending.","Replace sentinel Symbols with plain strings or numeric enums.","Run a deep pre-check (same walk as pushValue) on complex inputs.","Remember JSON.stringify drops Symbols — mirror that in your own sanitizing."],"tags":["types","javascript","wasm-worker","conversion"],"backgroundTag":"type-mismatch","analyzedSha":"adc986b362e3961f407868cb118a99fe831b9e61","analyzedAt":"2026-09-13T19:19:18.698Z","contentChangedAt":"2026-09-13T19:19:18.698Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}