colinhacks/zod · error · Error
Transforms cannot be represented in JSON Schema
Error message
Transforms cannot be represented in JSON Schema
What it means
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.
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.
Example fix
// before (throws on output side)
const Schema = z.string().datetime().transform((s) => new Date(s));
z.toJSONSchema(Schema);
// after (export the input shape)
const Schema = z.string().datetime().transform((s) => new Date(s));
z.toJSONSchema(Schema, { io: 'input' });
// { type: 'string', format: 'date-time' } Defensive patterns
Strategy: try-catch
Validate before calling
// Export the input (wire) shape to avoid the transform representation problem.
const json = z.toJSONSchema(schema, { io: 'input' });
// Or detect transforms and opt into the any fallback.
const opts = schemaContains(schema, (s) => s._zod.def.type === 'transform')
? { io: 'input' }
: {};
const json2 = z.toJSONSchema(schema, opts); Type guard
function hasTransform(schema) {
return schema._zod.traits.has('$ZodTransform');
} Try / catch
try {
return z.toJSONSchema(schema);
} catch (e) {
if (e.message === 'Transforms cannot be represented in JSON Schema') {
// The input (pre-transform) shape is usually the correct external contract
return z.toJSONSchema(schema, { io: 'input' });
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Schemas built for internal parsing that also drive API docs — the transform is implementation detail but blocks JSON Schema generation.
Related errors
- BigInt cannot be represented in JSON Schema
- BigInt literals cannot be represented in JSON Schema
- Custom types cannot be represented in JSON Schema
- Date cannot be represented in JSON Schema
- Dynamic catch values are not supported in JSON Schema
AI-assisted analysis of colinhacks/zod@2d90846af9 (2026-08-11).
Data as JSON: /api/errors/cfcb0d093649c23d.
Report an issue: GitHub.
Appendix: source
Thrown at packages/zod/src/v4/core/json-schema-processors.ts:258
export const successProcessor: Processor<schemas.$ZodSuccess> = (_schema, _ctx, json, _params) => {
(json as JSONSchema.BooleanSchema).type = "boolean";
};
export const customProcessor: Processor<schemas.$ZodCustom> = (_schema, ctx, _json, _params) => {
if (ctx.unrepresentable === "throw") {
throw new Error("Custom types cannot be represented in JSON Schema");
}
};
export const functionProcessor: Processor<schemas.$ZodFunction> = (_schema, ctx, _json, _params) => {
if (ctx.unrepresentable === "throw") {
throw new Error("Function types cannot be represented in JSON Schema");
}
};
export const transformProcessor: Processor<schemas.$ZodTransform> = (_schema, ctx, _json, _params) => {
if (ctx.unrepresentable === "throw") {
throw new Error("Transforms cannot be represented in JSON Schema");
}
};
export const mapProcessor: Processor<schemas.$ZodMap> = (_schema, ctx, _json, _params) => {
if (ctx.unrepresentable === "throw") {
throw new Error("Map cannot be represented in JSON Schema");
}
};
export const setProcessor: Processor<schemas.$ZodSet> = (_schema, ctx, _json, _params) => {
if (ctx.unrepresentable === "throw") {
throw new Error("Set cannot be represented in JSON Schema");
}
};
// ==================== COMPOSITE TYPE PROCESSORS ====================
export const arrayProcessor: Processor<schemas.$ZodArray> = (schema, ctx, _json, params) => {View on GitHub (pinned to 2d90846af9)