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
- Pass { unrepresentable: 'any' } to toJSONSchema() so the set field becomes {}.
- Model the external contract as z.array(elementSchema) (optionally with a uniqueness note/refine) and convert to/from Set at the boundary.
- 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
- Model external contracts with z.array(elementSchema) instead of z.set().
- Convert Set <-> Array at the boundary; keep z.set() for runtime-only schemas.
- Use an override() vendor extension (x-unique-items) if uniqueness must be conveyed to consumers.
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
- BigInt cannot be represented in JSON Schema
- BigInt literals cannot be represented in JSON Schema
- Custom types cannot be represented in JSON Schema
- Date cannot be represented in JSON Schema
- Dynamic catch values are not supported in JSON Schema
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)