Fix Zod v4 oneOf unions in strict schemas#1896
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6713349141
ℹ️ 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".
| // Handle unions (OpenAI strict mode supports anyOf, but not oneOf) | ||
| const oneOf = jsonSchema.oneOf; | ||
| if (Array.isArray(oneOf)) { | ||
| jsonSchema.anyOf = Array.isArray(jsonSchema.anyOf) ? [...jsonSchema.anyOf, ...oneOf] : oneOf; |
There was a problem hiding this comment.
Preserve oneOf semantics when anyOf already exists
When a schema contains both anyOf and oneOf, this change concatenates the oneOf variants into anyOf, which weakens validation semantics from “must satisfy both keywords” to a single OR over all variants. In JSON Schema, anyOf and oneOf are independent constraints, so merging them can make previously invalid data pass validation. This can silently broaden accepted outputs for mixed-composition schemas rather than only translating unsupported oneOf usage.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed in 2957e7f. The oneOf rewrite now preserves mixed-composition semantics instead of flattening into an existing anyOf: standalone oneOf becomes an allOf of anyOf plus a not(any overlap) exclusivity guard, and when a schema already has anyOf we keep that as a separate allOf term rather than merging the variants. Added regression coverage for mixed anyOf/oneOf schemas, and yarn jest tests/helpers/zod.test.ts --runInBand plus yarn jest tests/lib/transform.test.ts tests/helpers/zod.test.ts --runInBand pass.
Closes #1709
Zod v4 can emit
oneOffor discriminated unions, but strict OpenAI schemas supportanyOfinstead. This convertsoneOfunions before the existing strict-schema recursion runs, so nested discriminated unions are still processed normally.Verification:
yarn jest tests/helpers/zod.test.ts --runInBandyarn jest tests/lib/transform.test.ts tests/helpers/zod.test.ts --runInBandgit diff --check