colinhacks/zod · error · Error
NaN cannot be represented in JSON Schema
Error message
NaN cannot be represented in JSON Schema
What it means
`NaN` is not a valid JSON number, so `nanProcessor` (json-schema-processors.ts:202) refuses `z.nan()` when `ctx.unrepresentable === "throw"` (default). There is no faithful JSON Schema for 'not-a-number'.
Source
Thrown at packages/zod/src/v4/core/json-schema-processors.ts:204
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 {
if (vals.every((v) => typeof v === "number")) json.type = "number";
if (vals.every((v) => typeof v === "string")) json.type = "string";
if (vals.every((v) => typeof v === "boolean")) json.type = "boolean";
if (vals.every((v) => v === null)) json.type = "null";
json.enum = vals;
}
};
export const nanProcessor: Processor<schemas.$ZodNaN> = (_schema, ctx, _json, _params) => {
if (ctx.unrepresentable === "throw") {
throw new Error("NaN cannot be represented in JSON Schema");
}
};
export const templateLiteralProcessor: Processor<schemas.$ZodTemplateLiteral> = (schema, _ctx, json, _params) => {
const _json = json as JSONSchema.StringSchema;
const pattern = schema._zod.pattern;
if (!pattern) throw new Error("Pattern not found in template literal");
_json.type = "string";
_json.pattern = pattern.source;
};
export const fileProcessor: Processor<schemas.$ZodFile> = (schema, _ctx, json, _params) => {
const _json = json as JSONSchema.StringSchema;
const file: JSONSchema.StringSchema = {
type: "string",
format: "binary",
contentEncoding: "binary",
};View on GitHub (pinned to 912f0f51b0)
Solutions
- Use `{ unrepresentable: "any" }` to emit an empty schema for the NaN node.
- Strip the NaN branch from the union before conversion and normalize NaN to null/-1 at the boundary.
- If NaN must be representable, encode it as a sentinel string literal and document it.
Example fix
// before
z.toJSONSchema(z.union([z.number(), z.nan()])); // throws
// after
z.toJSONSchema(z.union([z.number(), z.nan()]), { unrepresentable: "any" }); Defensive patterns
Strategy: fallback
Validate before calling
const json = z.toJSONSchema(schema, { unrepresentable: "any" }); Type guard
function usesNaN(schema: z.ZodType): boolean {
return schema._zod.traits.has("$ZodNaN");
} Try / catch
try {
return z.toJSONSchema(schema);
} catch (e) {
if (e instanceof Error && /cannot be represented in JSON Schema/.test(e.message)) {
return z.toJSONSchema(schema, { unrepresentable: "any" });
}
throw e;
} Prevention
- Strip `z.nan()` branches from unions before conversion.
- Normalize NaN to a sentinel (null / specific number / string) at the boundary.
- Use `{ unrepresentable: "any" }` for schemas that must retain a NaN branch.
When it happens
Trigger: `z.toJSONSchema()` over a schema containing `z.nan()`, typically in a union like `z.union([z.number(), z.nan()])`, with default options.
Common situations: Schemas that explicitly accept NaN (e.g. from numeric parsers or ML pipelines) being converted to a shared contract.
Related errors
- BigInt cannot be represented in JSON Schema
- Symbols cannot be represented in JSON Schema
- Undefined cannot be represented in JSON Schema
- Void cannot be represented in JSON Schema
- Date cannot be represented in JSON Schema
AI-assisted analysis of colinhacks/zod@912f0f51b0 (2026-08-03).
Data as JSON: /data/errors/25a6f2edda964aaa.json.
Report an issue: GitHub.