colinhacks/zod · error · Error

Set cannot be represented in JSON Schema

Error message

Set cannot be represented in JSON Schema

What it means

Thrown by toJSONSchema() when a ZodSet schema (z.set(elementSchema)) is encountered with unrepresentable 'throw' (default). JSON has no Set type — arrays do not enforce uniqueness — so a typed Set cannot be faithfully expressed in JSON Schema.

Solutions

  1. Pass { unrepresentable: 'any' } to toJSONSchema() so the set field becomes {}.
  2. Model the external contract as z.array(elementSchema) (optionally with a uniqueness note/refine) and convert to/from Set at the boundary.
  3. If uniqueness must be conveyed, use a custom override() to attach a vendor extension (e.g. x-unique-items: true).

Example fix

// before (throws)
const Schema = z.set(z.string());
z.toJSONSchema(Schema);

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

Strategy: try-catch

Validate before calling

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

Type guard

function hasSet(schema) {
  return schema._zod.def.type === 'set';
}

Try / catch

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

Prevention

When it happens

Trigger: Calling toJSONSchema() on z.set(z.string()) or a schema that embeds a set field. Documenting an API whose runtime model uses Set for deduplication.

Common situations: Tag/collection fields modelled as Set at runtime, then exported to JSON Schema where the consumer expects an array.

Related errors


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

Appendix: source

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

    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;

  json.type = "array";
  json.items = process(def.element, ctx as any, {
    ...params,
    path: [...params.path, "items"],
  });
};

View on GitHub (pinned to 2d90846af9)