fix: prevent circular $ref in zodTextFormat for branded types#1777
fix: prevent circular $ref in zodTextFormat for branded types#1777fuleinist wants to merge 1 commit intoopenai:masterfrom
Conversation
Fixes openai#1739 When using z.string().brand(), zodTextFormat was creating a self-referencing $ref definition. Now extracts the underlying type correctly by treating branded types as transparent wrappers.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 457f908b77
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if ((def as any).typeName === ZodFirstPartyTypeKind.ZodBranded) { | ||
| return parseDef((def as any).type._def, refs, forceResolution); |
There was a problem hiding this comment.
Preserve branded schema metadata when unwrapping
Returning immediately for ZodBranded bypasses the addMeta(def, refs, jsonSchema) block below, so metadata defined on the branded wrapper (not the inner type) is silently dropped. This changes output for schemas like z.string().brand(...).describe("..."), where description/markdownDescription used to be emitted from the branded def but now disappear, which can materially change generated JSON schema guidance in zodTextFormat/zodResponseFormat.
Useful? React with 👍 / 👎.
Summary
Fixes circular
$refgeneration inzodTextFormatwhen using Zod branded types (e.g.,z.string().brand()).Problem
When using a branded type like
z.string().brand("SlideId">())and reusing it multiple times in a schema,zodTextFormatwas generating a circular$refthat references itself:{ "definitions": { "test_properties_a": { "$ref": "#/definitions/test_properties_a" } } }This circular reference is invalid and cannot be resolved.
Root Cause
The issue was in
parseDeffunction in the vendoredzod-to-json-schemapackage. When parsing a branded type:refs.seenwith the current pathparseBrandedDefthen parsed the underlying type, which also got added torefs.seenwith the SAME path$refwas created pointing to that pathrefs.seenat that same path, causing a circular referenceSolution
Modified
parseDefto treat branded types as transparent wrappers. When a branded type is encountered, it now directly parses the underlying type without adding the branded def torefs.seen. This prevents the circular reference issue.Changes
src/_vendor/zod-to-json-schema/parseDef.tsto handleZodBrandedtypes specially by parsing the underlying type directlyTesting
Verified with the reproduction case from the issue - no more circular references in the generated schema.
Fixes #1739