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

  1. If the schema is recursive, convert with `{ cycles: 'ref' }` so cycles become `$ref`s instead of live links.
  2. Inspect `.meta(...)` values (examples, default, custom fields) and ensure they are plain JSON-serializable (strings/numbers/booleans/arrays/plain objects) — remove functions, Dates, BigInts.
  3. 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

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


AI-assisted analysis of colinhacks/zod@912f0f51b0 (2026-08-03). Data as JSON: /data/errors/53c242ee4c5353cc.json. Report an issue: GitHub.