colinhacks/zod · error · Error

Map cannot be represented in JSON Schema

Error message

Map cannot be represented in JSON Schema

What it means

Thrown by toJSONSchema() when a ZodMap schema (z.map(keySchema, valueSchema)) is encountered with unrepresentable 'throw' (default). JSON objects only allow string keys and have no first-class map type with per-key validation, so a typed Map cannot be faithfully expressed (especially with non-string keys).

Solutions

  1. Pass { unrepresentable: 'any' } to toJSONSchema() so the map field becomes {}.
  2. Model the external contract as z.record(z.string(), valueSchema) (JSON object with string keys) and convert to/from Map at the boundary.
  3. If keys are enumerable, use z.object({ ... }) or an enum-keyed record instead.

Example fix

// before (throws)
const Schema = z.map(z.string(), z.number());
z.toJSONSchema(Schema);

// after (record for the JSON contract)
const Schema = z.record(z.string(), z.number());
z.toJSONSchema(Schema);
// { type: 'object', additionalProperties: { type: 'number' } }
Defensive patterns

Strategy: try-catch

Validate before calling

const opts = schemaContains(schema, (s) => s._zod.def.type === 'map')
  ? { unrepresentable: 'any' }
  : {};
const json = z.toJSONSchema(schema, opts);

Type guard

function hasMap(schema) {
  return schema._zod.def.type === 'map';
}

Try / catch

try {
  return z.toJSONSchema(schema);
} catch (e) {
  if (e.message === 'Map cannot be represented in JSON Schema') {
    return z.toJSONSchema(schema, { unrepresentable: 'any' });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling toJSONSchema() on z.map(z.string(), z.number()) or any schema embedding a z.map(). OpenAPI generation for an API whose body uses Map.

Common situations: Runtime schemas that exploit Map for arbitrary-key lookups, then needing JSON Schema/OpenAPI output that downstream tooling can consume.

Related errors


AI-assisted analysis of colinhacks/zod@2d90846af9 (2026-08-11). Data as JSON: /api/errors/33ed11f9b31c922b. Report an issue: GitHub.

Appendix: source

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

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

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

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

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

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

// ==================== COMPOSITE TYPE PROCESSORS ====================

export const arrayProcessor: Processor<schemas.$ZodArray> = (schema, ctx, _json, params) => {
  const json = _json as JSONSchema.ArraySchema;
  const def = schema._zod.def as schemas.$ZodArrayDef;
  const { minimum, maximum } = schema._zod.bag;
  if (typeof minimum === "number") json.minItems = minimum;
  if (typeof maximum === "number") json.maxItems = maximum;

View on GitHub (pinned to 2d90846af9)