{"record":{"id":"05a50cbb8b81626b","repo":"colinhacks/zod","slug":"symbols-cannot-be-represented-in-json-schema","errorCode":null,"errorMessage":"Symbols cannot be represented in JSON Schema","messagePattern":"Symbols cannot be represented in JSON Schema","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/zod/src/v4/core/json-schema-processors.ts","lineNumber":110,"sourceCode":"    json.maximum = maximum;\n  }\n\n  if (typeof multipleOf === \"number\") json.multipleOf = multipleOf;\n};\n\nexport const booleanProcessor: Processor<schemas.$ZodBoolean> = (_schema, _ctx, json, _params) => {\n  (json as JSONSchema.BooleanSchema).type = \"boolean\";\n};\n\nexport const bigintProcessor: Processor<schemas.$ZodBigInt> = (_schema, ctx, _json, _params) => {\n  if (ctx.unrepresentable === \"throw\") {\n    throw new Error(\"BigInt cannot be represented in JSON Schema\");\n  }\n};\n\nexport const symbolProcessor: Processor<schemas.$ZodSymbol> = (_schema, ctx, _json, _params) => {\n  if (ctx.unrepresentable === \"throw\") {\n    throw new Error(\"Symbols cannot be represented in JSON Schema\");\n  }\n};\n\nexport const nullProcessor: Processor<schemas.$ZodNull> = (_schema, ctx, json, _params) => {\n  if (ctx.target === \"openapi-3.0\") {\n    json.type = \"string\";\n    json.nullable = true;\n    json.enum = [null];\n  } else {\n    json.type = \"null\";\n  }\n};\n\nexport const undefinedProcessor: Processor<schemas.$ZodUndefined> = (_schema, ctx, _json, _params) => {\n  if (ctx.unrepresentable === \"throw\") {\n    throw new Error(\"Undefined cannot be represented in JSON Schema\");\n  }\n};","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/colinhacks/zod/blob/2d90846af918af9602e088812d63a035d47cdbe4/packages/zod/src/v4/core/json-schema-processors.ts#L92-L128","documentation":"Thrown by toJSONSchema() when a ZodSymbol schema (z.symbol()) is encountered and unrepresentable is 'throw' (default). Symbols are a JavaScript runtime concept with no JSON or JSON Schema equivalent, so conversion is refused.","triggerScenarios":"Calling toJSONSchema() on a schema that contains z.symbol(), e.g. a model keyed by Symbol-valued discriminators. Exporting a registry that mixes symbol fields into its type.","commonSituations":"Internal schemas that use symbols as opaque tokens, then feeding the same schema to a JSON-Schema-based validator or doc generator.","solutions":["Pass { unrepresentable: 'any' } to toJSONSchema() so symbol fields become {}.","Strip symbol fields from the schema used for JSON export; model the external contract with z.string() instead.","Split the runtime schema from the export schema so symbols never reach toJSONSchema()."],"exampleFix":"// before (throws)\nconst Schema = z.object({ tag: z.symbol() });\nz.toJSONSchema(Schema);\n\n// after\nconst Schema = z.object({ tag: z.symbol() });\nz.toJSONSchema(Schema, { unrepresentable: 'any' });","handlingStrategy":"try-catch","validationCode":"const opts = schemaContains(schema, (s) => s._zod.def.type === 'symbol')\n  ? { unrepresentable: 'any' }\n  : {};\nconst json = z.toJSONSchema(schema, opts);","typeGuard":"function hasSymbol(schema) {\n  return schema._zod.def.type === 'symbol';\n}","tryCatchPattern":"try {\n  return z.toJSONSchema(schema);\n} catch (e) {\n  if (e.message === 'Symbols cannot be represented in JSON Schema') {\n    return z.toJSONSchema(schema, { unrepresentable: 'any' });\n  }\n  throw e;\n}","preventionTips":["Keep symbol fields in runtime-only schemas; strip them before JSON Schema export.","Default to { unrepresentable: 'any' } for schemas that may carry opaque tokens.","Maintain separate export schemas for external contracts."],"tags":["json-schema","symbol","unrepresentable","to-json-schema"],"backgroundTag":null,"analyzedSha":"2d90846af918af9602e088812d63a035d47cdbe4","analyzedAt":"2026-08-11T01:21:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}