colinhacks/zod · error · Error
Duplicate schema id "${id}" detected during JSON Schema conv
Error message
Duplicate schema id "${id}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together. What it means
Thrown in `extractDefs` during JSON-Schema conversion. Zod scans every schema it has seen and collects their `.meta({ id })` values; if two distinct schema objects share the same `id`, conversion aborts because the `$defs`/`definitions` keys would collide and `$ref`s would be ambiguous. Ids must be unique across all schemas converted together.
Source
Thrown at packages/zod/src/v4/core/to-json-schema.ts:234
export function extractDefs<T extends schemas.$ZodType>(
ctx: ToJSONSchemaContext,
schema: T
// params: EmitParams
): void {
// iterate over seen map;
const root = ctx.seen.get(schema);
if (!root) throw new Error("Unprocessed schema. This is a bug in Zod.");
// Track ids to detect duplicates across different schemas
const idToSchema = new Map<string, schemas.$ZodType>();
for (const entry of ctx.seen.entries()) {
const id = ctx.metadataRegistry.get(entry[0])?.id;
if (id) {
const existing = idToSchema.get(id);
if (existing && existing !== entry[0]) {
throw new Error(
`Duplicate schema id "${id}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`
);
}
idToSchema.set(id, entry[0]);
}
}
// returns a ref to the schema
// defId will be empty if the ref points to an external schema (or #)
const makeURI = (entry: [schemas.$ZodType<unknown, unknown>, Seen]): { ref: string; defId?: string } => {
// comparing the seen objects because sometimes
// multiple schemas map to the same seen object.
// e.g. lazy
// external is configured
const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions";
if (ctx.external) {
const externalId = ctx.external.registry.get(entry[0])?.id; // ?? "__shared";// `__schema${ctx.counter++}`;View on GitHub (pinned to 912f0f51b0)
Solutions
- Give each schema a globally unique `id` in its `.meta({ id })` call.
- Search the codebase for the duplicate id reported in the message and rename one of them.
- If two schemas are genuinely meant to be the same, share a single schema object/reference rather than defining two with the same id.
Example fix
// before
const A = z.object({ name: z.string() }).meta({ id: 'User' });
const B = z.object({ email: z.string() }).meta({ id: 'User' });
z.toJSONSchema(z.object({ a: A, b: B })); // throws
// after
const A = z.object({ name: z.string() }).meta({ id: 'NamedUser' });
const B = z.object({ email: z.string() }).meta({ id: 'EmailUser' });
z.toJSONSchema(z.object({ a: A, b: B })); Defensive patterns
Strategy: validation
Validate before calling
function assertUniqueIds(schemas) {
const seen = new Map();
for (const s of schemas) {
const id = s._zod?.def?.meta?.id ?? (s as any).meta?.id;
// id is usually registered via .meta({ id }); check via the registry if available
if (id && seen.has(id) && seen.get(id) !== s) throw new Error(`duplicate id "${id}"`);
if (id) seen.set(id, s);
}
} Try / catch
try {
z.toJSONSchema(root);
} catch (e) {
if (e instanceof Error && e.message.startsWith('Duplicate schema id')) {
// grep the codebase for the reported id and rename one occurrence
}
throw e;
} Prevention
- Give every schema with .meta({ id }) a globally unique id.
- Centralize id constants in one module to avoid accidental reuse.
- Share a single schema object across references instead of redefining with the same id.
When it happens
Trigger: Registering two different schemas with the same id, e.g. `A.meta({ id: 'User' })` and `B.meta({ id: 'User' })` where A and B are different objects, then converting a schema that references both (e.g. via intersection, union, or a shared registry).
Common situations: Reusing an id constant across modules; copying a schema definition and forgetting to change its id; merging schemas from multiple files that each tag their primary type with the same generic name like `'Item'`.
Related errors
- Schema is missing an `id` property
- [toJSONSchema]: Non-representable type encountered: ${def.ty
- Cycle detected: #/${seen.cycle?.join("/")}/<root> Set the `
- Error converting schema to JSON.
- External $ref is not supported, only local refs (#/...) are
AI-assisted analysis of colinhacks/zod@912f0f51b0 (2026-08-03).
Data as JSON: /data/errors/da72081f692c3ed2.json.
Report an issue: GitHub.