colinhacks/zod · error · Error
Function types cannot be represented in JSON Schema
Error message
Function types cannot be represented in JSON Schema
What it means
Thrown by toJSONSchema() when a ZodFunction schema (z.function(args, ret)) is encountered with unrepresentable 'throw' (default). JSON Schema describes data, not callable values, so function schemas have no representation.
Solutions
- Pass { unrepresentable: 'any' } to toJSONSchema() so function fields become {}.
- Separate the function signature from the data model: export only the argument and return schemas via toJSONSchema(), not the wrapping z.function().
- For OpenAPI, describe operations explicitly rather than converting z.function() schemas.
Example fix
// before (throws)
const Tool = z.object({
name: z.string(),
handler: z.function(z.tuple([z.string()]), z.void()),
});
z.toJSONSchema(Tool);
// after (export only the data contract)
const ToolArgs = z.tuple([z.string()]);
z.toJSONSchema(ToolArgs); Defensive patterns
Strategy: try-catch
Validate before calling
const opts = schemaContains(schema, (s) => s._zod.def.type === 'function')
? { unrepresentable: 'any' }
: {};
const json = z.toJSONSchema(schema, opts); Type guard
function hasFunction(schema) {
return schema._zod.def.type === 'function';
} Try / catch
try {
return z.toJSONSchema(schema);
} catch (e) {
if (e.message === 'Function types cannot be represented in JSON Schema') {
return z.toJSONSchema(schema, { unrepresentable: 'any' });
}
throw e;
} Prevention
- Do not embed z.function() in data schemas you export; export argument/return schemas separately.
- For OpenAPI, describe operations directly rather than converting z.function() schemas.
- Pass { unrepresentable: 'any' } when exporting registries that mix data and procedure schemas.
When it happens
Trigger: Calling toJSONSchema() on a schema that contains a z.function() field — common in RPC/tool schemas. Exporting an entire registry that includes procedure signatures.
Common situations: Tool-calling / MCP-style schemas where the top-level model embeds handler signatures, then feeding that model to a JSON Schema-based validator or doc generator.
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/40d2cba7e29d7e68.
Report an issue: GitHub.
Appendix: source
Thrown at packages/zod/src/v4/core/json-schema-processors.ts:252
}
} else {
Object.assign(_json, file);
}
};
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");View on GitHub (pinned to 2d90846af9)