colinhacks/zod · error · Error

Date cannot be represented in JSON Schema

Error message

Date cannot be represented in JSON Schema

What it means

JSON has no native date type (dates are conventionally ISO strings), so Zod will not guess a representation: `dateProcessor` (json-schema-processors.ts:148) throws for `z.date()` when `ctx.unrepresentable === "throw"` (default). Unlike bigint/symbol, a clean replacement exists (`z.iso.datetime()` or `z.string().datetime()`).

Source

Thrown at packages/zod/src/v4/core/json-schema-processors.ts:150

    throw new Error("Void cannot be represented in JSON Schema");
  }
};

export const neverProcessor: Processor<schemas.$ZodNever> = (_schema, _ctx, json, _params) => {
  json.not = {};
};

export const anyProcessor: Processor<schemas.$ZodAny> = (_schema, _ctx, _json, _params) => {
  // empty schema accepts anything
};

export const unknownProcessor: Processor<schemas.$ZodUnknown> = (_schema, _ctx, _json, _params) => {
  // empty schema accepts anything
};

export const dateProcessor: Processor<schemas.$ZodDate> = (_schema, ctx, _json, _params) => {
  if (ctx.unrepresentable === "throw") {
    throw new Error("Date cannot be represented in JSON Schema");
  }
};

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") {

View on GitHub (pinned to 912f0f51b0)

Solutions

  1. For conversion only, call `z.toJSONSchema(schema, { unrepresentable: "any" })`.
  2. Preferably replace `z.date()` with `z.iso.datetime()` (or `z.string().datetime()`) so the contract uses the standard `date-time` JSON Schema format.
  3. Keep `z.date()` at the runtime boundary and pipe/transform into a datetime string schema for the contract.

Example fix

// before
z.toJSONSchema(z.object({ createdAt: z.date() })); // throws
// after
z.toJSONSchema(z.object({ createdAt: z.iso.datetime() })); // -> { type: "string", format: "date-time" }
Defensive patterns

Strategy: fallback

Validate before calling

// Prefer a JSON-native datetime for contract schemas.
const contractSchema = z.object({ createdAt: z.iso.datetime() });
const json = z.toJSONSchema(contractSchema);

Type guard

function usesDate(schema: z.ZodType): boolean {
  return schema._zod.traits.has("$ZodDate");
}

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

When it happens

Trigger: `z.toJSONSchema()` over a schema containing `z.date()`, with default options. Very common in API schemas that model timestamps as JS Date objects.

Common situations: Generating OpenAPI for an endpoint that returns Date objects; sharing a Zod schema between a Node backend (uses Date) and a JSON Schema consumer.

Related errors


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