{"record":{"id":"cfcb0d093649c23d","repo":"colinhacks/zod","slug":"transforms-cannot-be-represented-in-json-schema","errorCode":null,"errorMessage":"Transforms cannot be represented in JSON Schema","messagePattern":"Transforms 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":258,"sourceCode":"export const successProcessor: Processor<schemas.$ZodSuccess> = (_schema, _ctx, json, _params) => {\n  (json as JSONSchema.BooleanSchema).type = \"boolean\";\n};\n\nexport const customProcessor: Processor<schemas.$ZodCustom> = (_schema, ctx, _json, _params) => {\n  if (ctx.unrepresentable === \"throw\") {\n    throw new Error(\"Custom types cannot be represented in JSON Schema\");\n  }\n};\n\nexport const functionProcessor: Processor<schemas.$ZodFunction> = (_schema, ctx, _json, _params) => {\n  if (ctx.unrepresentable === \"throw\") {\n    throw new Error(\"Function types cannot be represented in JSON Schema\");\n  }\n};\n\nexport const transformProcessor: Processor<schemas.$ZodTransform> = (_schema, ctx, _json, _params) => {\n  if (ctx.unrepresentable === \"throw\") {\n    throw new Error(\"Transforms cannot be represented in JSON Schema\");\n  }\n};\n\nexport const mapProcessor: Processor<schemas.$ZodMap> = (_schema, ctx, _json, _params) => {\n  if (ctx.unrepresentable === \"throw\") {\n    throw new Error(\"Map cannot be represented in JSON Schema\");\n  }\n};\n\nexport const setProcessor: Processor<schemas.$ZodSet> = (_schema, ctx, _json, _params) => {\n  if (ctx.unrepresentable === \"throw\") {\n    throw new Error(\"Set cannot be represented in JSON Schema\");\n  }\n};\n\n// ==================== COMPOSITE TYPE PROCESSORS ====================\n\nexport const arrayProcessor: Processor<schemas.$ZodArray> = (schema, ctx, _json, params) => {","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/colinhacks/zod/blob/2d90846af918af9602e088812d63a035d47cdbe4/packages/zod/src/v4/core/json-schema-processors.ts#L240-L276","documentation":"Thrown by toJSONSchema() when a ZodTransform schema (z.transform(...)) is encountered with unrepresentable 'throw' (default). A transform mutates the output type at runtime; the JSON Schema it would produce is the inner schema's, but the transform itself has no declarative representation and the converter surfaces the mismatch.","triggerScenarios":"Calling toJSONSchema() on a schema whose output side is a transform, e.g. z.string().transform((s) => new Date(s)), without selecting the input side. Exporting a piped schema that ends in a transform.","commonSituations":"Schemas built for internal parsing that also drive API docs — the transform is implementation detail but blocks JSON Schema generation.","solutions":["Pass io: 'input' to toJSONSchema() to convert the pre-transform shape (the wire format), which is usually what external consumers need.","Pass { unrepresentable: 'any' } so the transform collapses to {}.","Split the schema: keep a plain data schema for export, and apply the transform in a separate parsing-only schema."],"exampleFix":"// before (throws on output side)\nconst Schema = z.string().datetime().transform((s) => new Date(s));\nz.toJSONSchema(Schema);\n\n// after (export the input shape)\nconst Schema = z.string().datetime().transform((s) => new Date(s));\nz.toJSONSchema(Schema, { io: 'input' });\n// { type: 'string', format: 'date-time' }","handlingStrategy":"try-catch","validationCode":"// Export the input (wire) shape to avoid the transform representation problem.\nconst json = z.toJSONSchema(schema, { io: 'input' });\n// Or detect transforms and opt into the any fallback.\nconst opts = schemaContains(schema, (s) => s._zod.def.type === 'transform')\n  ? { io: 'input' }\n  : {};\nconst json2 = z.toJSONSchema(schema, opts);","typeGuard":"function hasTransform(schema) {\n  return schema._zod.traits.has('$ZodTransform');\n}","tryCatchPattern":"try {\n  return z.toJSONSchema(schema);\n} catch (e) {\n  if (e.message === 'Transforms cannot be represented in JSON Schema') {\n    // The input (pre-transform) shape is usually the correct external contract\n    return z.toJSONSchema(schema, { io: 'input' });\n  }\n  throw e;\n}","preventionTips":["When exporting, prefer io: 'input' for schemas that pipe into transforms — the wire format is what consumers validate against.","Keep transforms in a separate runtime schema; export a plain data schema.","Pass { unrepresentable: 'any' } as a last resort to emit {} for transform tails."],"tags":["json-schema","transform","pipe","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"}