colinhacks/zod · error · Error
BigInt literals cannot be represented in JSON Schema
Error message
BigInt literals cannot be represented in JSON Schema
What it means
Thrown by the literalProcessor when a ZodLiteral's accepted values include a bigint (e.g. z.literal(1n)) and unrepresentable is 'throw' (default). BigInt is not a JSON type, so it cannot appear in a JSON Schema const/enum.
Solutions
- Pass { unrepresentable: 'any' } to toJSONSchema(); the bigint entry is dropped from the literal's values.
- For the external contract, model the value as a string or number literal (z.literal('1') or z.literal(1)) and convert at the boundary.
- Split runtime and export schemas so bigint literals never reach toJSONSchema().
Example fix
// before (throws)
const Schema = z.literal(1n);
z.toJSONSchema(Schema);
// after
const Schema = z.literal(1n);
z.toJSONSchema(Schema, { unrepresentable: 'any' }); // yields {}
// or use a numeric literal for the contract
const External = z.literal(1); Defensive patterns
Strategy: try-catch
Validate before calling
const opts = schemaContains(schema, (s) =>
s._zod.def.type === 'literal' && [...s.values].some((v) => typeof v === 'bigint'))
? { unrepresentable: 'any' }
: {};
const json = z.toJSONSchema(schema, opts); Type guard
function hasBigintLiteral(schema) {
if (schema._zod.def.type !== 'literal') return false;
const def = schema._zod.def;
return Array.isArray(def.values) && def.values.some((v) => typeof v === 'bigint');
} Try / catch
try {
return z.toJSONSchema(schema);
} catch (e) {
if (e.message === 'BigInt literals cannot be represented in JSON Schema') {
return z.toJSONSchema(schema, { unrepresentable: 'any' });
}
throw e;
} Prevention
- Use string or number literals in export schemas; convert bigint at the boundary.
- Keep bigint-literal schemas runtime-only.
- Default to { unrepresentable: 'any' } when exporting models that may include bigint sentinels.
When it happens
Trigger: Calling toJSONSchema() on z.literal(1n) or z.literal([1n, 2n]). A model whose discriminating literal is a bigint.
Common situations: Domain models that use bigint literals for opaque IDs/codes, then feeding the same schema to a JSON Schema or OpenAPI generator.
Related errors
- BigInt cannot be represented in JSON Schema
- Literal `undefined` 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/75c2c37fd6f5c60f.
Report an issue: GitHub.
Appendix: source
Thrown at packages/zod/src/v4/core/json-schema-processors.ts:175
// Number enums can have both string and number values
if (values.every((v) => typeof v === "number")) json.type = "number";
if (values.every((v) => typeof v === "string")) json.type = "string";
json.enum = values;
};
export const literalProcessor: Processor<schemas.$ZodLiteral> = (schema, ctx, json, _params) => {
const def = schema._zod.def as schemas.$ZodLiteralDef<any>;
const vals: (string | number | boolean | null)[] = [];
for (const val of def.values) {
if (val === undefined) {
if (ctx.unrepresentable === "throw") {
throw new Error("Literal `undefined` cannot be represented in JSON Schema");
} else {
// do not add to vals
}
} else if (typeof val === "bigint") {
if (ctx.unrepresentable === "throw") {
throw new Error("BigInt literals cannot be represented in JSON Schema");
} else {
vals.push(Number(val));
}
} else {
vals.push(val);
}
}
if (vals.length === 0) {
// do nothing (an undefined literal was stripped)
} else if (vals.length === 1) {
const val = vals[0]!;
json.type = val === null ? ("null" as const) : (typeof val as any);
if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
json.enum = [val];
} else {
json.const = val;
}
} else {View on GitHub (pinned to 2d90846af9)