colinhacks/zod · error · Error
Literal `undefined` cannot be represented in JSON Schema
Error message
Literal `undefined` cannot be represented in JSON Schema
What it means
Thrown by the literalProcessor when a ZodLiteral's accepted values include the JavaScript undefined value and unrepresentable is 'throw' (default). JSON Schema const/enum cannot express undefined (it is not JSON), so the converter refuses rather than emit a const: undefined that downstream tools would misread.
Solutions
- Pass { unrepresentable: 'any' } to toJSONSchema(); the undefined entry is dropped silently from the literal's values.
- For the exported contract, replace z.literal(undefined) with z.literal(null) or omit the key (z.optional) to express absence portably.
- Branch the schema so the export variant contains only JSON-valid literals.
Example fix
// before (throws)
const Schema = z.literal(undefined);
z.toJSONSchema(Schema);
// after
const Schema = z.literal(undefined);
z.toJSONSchema(Schema, { unrepresentable: 'any' }); // yields {}
// or use null for the external contract
const External = z.literal(null); Defensive patterns
Strategy: try-catch
Validate before calling
const opts = schemaContains(schema, (s) =>
s._zod.def.type === 'literal' && [...s.values].includes(undefined))
? { unrepresentable: 'any' }
: {};
const json = z.toJSONSchema(schema, opts); Type guard
function hasUndefinedLiteral(schema) {
if (schema._zod.def.type !== 'literal') return false;
const def = schema._zod.def;
return Array.isArray(def.values) && def.values.includes(undefined);
} Try / catch
try {
return z.toJSONSchema(schema);
} catch (e) {
if (e.message === 'Literal `undefined` cannot be represented in JSON Schema') {
return z.toJSONSchema(schema, { unrepresentable: 'any' });
}
throw e;
} Prevention
- Avoid undefined as a literal value in schemas you intend to export.
- Use z.literal(null) or z.optional() to express absence in external contracts.
- Pass { unrepresentable: 'any' } when exporting schemas with sentinel undefined literals.
When it happens
Trigger: Calling toJSONSchema() on z.literal(undefined) or z.literal([undefined, 'x']). A schema that discriminates on 'this literal is undefined' for an external contract.
Common situations: Using undefined as a sentinel literal value internally, then exporting the same schema for API documentation or to drive a JSON-Schema validator.
Related errors
- BigInt literals cannot be represented in JSON Schema
- Undefined cannot be represented in JSON Schema
- BigInt cannot be represented in JSON Schema
- Custom types cannot be represented in JSON Schema
- Date cannot be represented in JSON Schema
AI-assisted analysis of colinhacks/zod@2d90846af9 (2026-08-11).
Data as JSON: /api/errors/631f1e922a00d60b.
Report an issue: GitHub.
Appendix: source
Thrown at packages/zod/src/v4/core/json-schema-processors.ts:169
}
};
export const enumProcessor: Processor<schemas.$ZodEnum> = (schema, _ctx, json, _params) => {
const def = schema._zod.def as schemas.$ZodEnumDef;
const values = getEnumValues(def.entries);
// 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);View on GitHub (pinned to 2d90846af9)