toJSONSchema deletes an id explicitly set by override
Since 4.4.0 (#5759), toJSONSchema deletes a caller-assigned id when it matches the definition name. Verified on draft-07 and draft-2020-12: preserved through 4.3.6, removed in 4.4.0 and still affected in 4.6.5.
Reproduction with [email protected]:
import { z } from 'zod';
const schema = z.string();
const registry = z.registry();
registry.add(schema, { id: 'Example' });
for (const target of ['draft-07', 'draft-2020-12']) {
const result = z.toJSONSchema(schema, {
target,
metadata: registry,
override: ({ jsonSchema }) => { jsonSchema.id = 'Example'; },
});
const body = result.definitions?.Example ?? result.$defs?.Example ?? result;
console.log(target, body.id); // Expected: 'Example'; actual: undefined
}
Changing the override value to 'Other' preserves it. Here id is a custom annotation. Cleanup runs after override and uses value equality to decide whether the field belongs to Zod.
We investigated this after upgrading Zod caused OpenAPI generation to fail in our application. Our existing Fastify adapter reads .meta({ $id }), supplies registry id to name definitions, then previously renamed the emitted root id to $id for Fastify registration. We will fix our reliance on that emitted field. The reproduction adds an explicit override, which our adapter does not use, to demonstrate the separate deletion of caller-authored output.
Please use $zod.-prefixed intermediary keys, or separate internal storage, so cleanup removes only Zod-owned data and preserves explicit overrides. The public registry id API can remain unchanged.
Source: colinhacks/zod