colinhacks/zod · error · Error
Error converting schema to JSON.
Error message
Error converting schema to JSON.
What it means
Thrown as a fallback when `JSON.parse(JSON.stringify(result))` fails at the very end of `z.toJSONSchema()`. The conversion produces a result object that cannot be serialized to JSON — typically because an unhandled circular reference remains in the output (a cycle that wasn't extracted to a `$ref`), or because the schema metadata contains non-serializable values like functions, `Date` objects in unexpected places, or `BigInt`.
Source
Thrown at packages/zod/src/v4/core/to-json-schema.ts:522
// this "finalizes" this schema and ensures all cycles are removed
// each call to finalize() is functionally independent
// though the seen map is shared
const finalized = JSON.parse(JSON.stringify(result));
Object.defineProperty(finalized, "~standard", {
value: {
...schema["~standard"],
jsonSchema: {
input: createStandardJSONSchemaMethod(schema, "input", ctx.processors),
output: createStandardJSONSchemaMethod(schema, "output", ctx.processors),
},
},
enumerable: false,
writable: false,
});
return finalized;
} catch (_err) {
throw new Error("Error converting schema to JSON.");
}
}
function isTransforming(
_schema: schemas.$ZodType,
_ctx?: {
seen: Set<schemas.$ZodType>;
}
): boolean {
const ctx = _ctx ?? { seen: new Set() };
if (ctx.seen.has(_schema)) return false;
ctx.seen.add(_schema);
const def = (_schema as schemas.$ZodTypes)._zod.def;
if (def.type === "transform") return true;
View on GitHub (pinned to 912f0f51b0)
Solutions
- If the schema is recursive, convert with `{ cycles: 'ref' }` so cycles become `$ref`s instead of live links.
- Inspect `.meta(...)` values (examples, default, custom fields) and ensure they are plain JSON-serializable (strings/numbers/booleans/arrays/plain objects) — remove functions, Dates, BigInts.
- If using a custom `toJSONSchema`/`processJSONSchema`, ensure its return value is acyclic and JSON-safe; call `JSON.stringify` on it yourself to debug.
Example fix
// before
const S = z.object({ a: z.string() }).meta({
examples: [{ a: 'x' }],
default: () => ({ a: '' }), // function — not serializable
});
z.toJSONSchema(S); // throws
// after
const S = z.object({ a: z.string() }).meta({
examples: [{ a: 'x' }],
default: { a: '' },
});
z.toJSONSchema(S); Defensive patterns
Strategy: validation
Validate before calling
function isJsonSafe(v, seen = new WeakSet()) {
if (v === null || typeof v !== 'object') return typeof v !== 'function' && typeof v !== 'bigint' || typeof v === 'bigint' ? false : true;
if (typeof v === 'function') return false;
if (seen.has(v)) return false;
seen.add(v);
for (const k in v) if (!isJsonSafe(v[k], seen)) return false;
return true;
}
// before converting, sanity-check the produced result manually:
// JSON.parse(JSON.stringify(z.toJSONSchema(schema, { cycles: 'ref' }))) Type guard
function isJsonSafe(v, seen = new WeakSet()): boolean {
if (v === null) return true;
const t = typeof v;
if (t === 'function' || t === 'bigint' || t === 'symbol') return false;
if (t !== 'object') return true;
if (seen.has(v)) return false;
seen.add(v);
return Object.values(v).every((x) => isJsonSafe(x, seen));
} Try / catch
try {
z.toJSONSchema(schema);
} catch (e) {
if (e instanceof Error && e.message === 'Error converting schema to JSON.') {
// retry with cycles:'ref', and strip non-serializable meta (functions, Dates, BigInt)
z.toJSONSchema(schema, { cycles: 'ref' });
}
throw e;
} Prevention
- Convert recursive schemas with cycles:'ref' so cycles become $refs.
- Keep .meta() values JSON-serializable (no functions, Dates, BigInt, class instances).
- Test toJSONSchema output by round-tripping through JSON.parse(JSON.stringify(...)).
When it happens
Trigger: A recursive schema converted without `cycles: 'ref'` leaving a live cycle in the output; attaching functions, class instances, or `BigInt` to schema metadata that gets spread into the JSON Schema; a custom `toJSONSchema` override returning an object with circular links.
Common situations: Custom schemas whose `toJSONSchema`/`processJSONSchema` returns non-serializable content; metadata (`examples`, `default`) holding functions or Dates; uncaught recursion when `cycles` handling didn't fire.
Related errors
- Cycle detected: #/${seen.cycle?.join("/")}/<root> Set the `
- fromJSONSchema input is not valid JSON (possibly cyclic); us
- [toJSONSchema]: Non-representable type encountered: ${def.ty
- Duplicate schema id "${id}" detected during JSON Schema conv
- Schema is missing an `id` property
AI-assisted analysis of colinhacks/zod@912f0f51b0 (2026-08-03).
Data as JSON: /data/errors/53c242ee4c5353cc.json.
Report an issue: GitHub.