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

  1. Pass { unrepresentable: 'any' } to toJSONSchema(); the bigint entry is dropped from the literal's values.
  2. 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.
  3. 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

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


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)