Skip to content

fix(zod): keep every declared tuple position - #2512

Merged
HAYDEN-OAI merged 3 commits into
openai:mainfrom
cmun2:fix/zod-tuple-positions
Sep 4, 2026
Merged

fix(zod): keep every declared tuple position#2512
HAYDEN-OAI merged 3 commits into
openai:mainfrom
cmun2:fix/zod-tuple-positions

Conversation

@cmun2

@cmun2 cmun2 commented Aug 28, 2026

Copy link
Copy Markdown
Contributor
  • I understand that this repository is auto-generated and my pull request may not be merged

Changes being requested

parseTupleDef in the vendored Zod v3 converter builds items with a map that drops any element whose parser returns undefined, while minItems and maxItems are taken from def.items.length. The two disagree whenever an element produces no schema.

zodToJsonSchema(z.tuple([z.void(), z.string()]));
// before
{ "type": "array", "items": [{ "type": "string" }], "minItems": 2, "maxItems": 2 }

// after
{ "type": "array", "items": [{}, { "type": "string" }], "minItems": 2, "maxItems": 2 }

The array-form items keyword is positional, so before this change the schema requires exactly two entries and describes the string element at index 0 — the position the void element occupies. A value the Zod schema accepts is rejected by the schema generated from it, and vice versa. The same shift happens with a rest element, where additionalItems then applies one position too early.

Keeping an unconstrained {} for such an element preserves the alignment and constrains nothing, which is what the element was already saying. Zod v4 describes both positions here, so this also brings the v3 output back in line with v4.

Tuples whose elements all produce schemas are unaffected; a test pins that.

Additional context & links

Split out of #2463. It surfaced there as a regression an earlier revision of that branch introduced, and while fixing it I found the same drop happens without any of that change — a tuple under an object property already hit it, because parseObjectDef has always set propertyPath. The repro above needs no property at all and reproduces on main as it stands. #2463 no longer touches parseDef.ts, so the path that first exposed this is gone from it entirely and the two are independent.

Scoped to one function in src/_vendor/zod-to-json-schema/parsers/tuple.ts.

Testing

  • pnpm vitest run tests/helpers/zod-tuple-positions.test.ts — 4 passed.
  • With the source change reverted and the tests kept, 3 of the 4 fail. The fourth is a control asserting that ordinary tuples do not change, so it passes either way.
  • Full suite: 5353 passed. The 26 failing files are identical to those on main at 222f3d7 and come from optional dependencies that are not installed in this environment (@aws-sdk/*, @smithy/*, ws).
  • ./scripts/lint and ./scripts/format: clean for both files.

`parseTupleDef` builds `items` with a `map` that drops any element whose
parser returns `undefined`, while `minItems` and `maxItems` are taken from
`def.items.length`. `z.tuple([z.void(), z.string()])` therefore converts to
an array that requires exactly two entries but describes only one position,
and the string element is described at index 0 where the void element sits.

Keeping an unconstrained `{}` for such an element preserves the alignment and
constrains nothing, which is what the element already said.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cmun2
cmun2 requested a review from a team as a code owner August 28, 2026 06:15
cmun2 added a commit to cmun2/openai-node that referenced this pull request Aug 28, 2026
Three things came out now that the decision is read off the emitted
document rather than inferred from `refs.seen`.

`Seen.propertyPath` and `Seen.referencePath` are written and never read.
They existed to carry the reference context forward; the emitted `$ref`
carries it instead. `Refs.ts` and `parseDef.ts` go back to their original
contents, so the converter's shared dispatch is untouched by this PR.

A recursive definition whose branch points back at itself was being read
as a call site outside a property, which kept the wrapper the inline
occurrence does not have. A definition describing itself does not decide
which encoding it owes; it still counts as a pointer for the stranding
check, where removing a wrapper strands a self-reference exactly as it
would an external one.

The tuple positioning fix is a separate, pre-existing bug -- it
reproduces with no part of this change applied -- and is now openai#2512.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@HAYDEN-OAI HAYDEN-OAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed tuple indexing and rest-element handling. The empty-schema fallback preserves declared positions without changing ordinary tuples. No substantive findings.

Static review; no tests executed.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Castiron custom code

✅ No new custom-code files detected.

32 mixed files remain; 0 existing customizations changed.

Compared dde19c5c7228a9fcd2137fd1. Generated baselines verified.

32 existing customizations unchanged
  • api.md
  • scripts/castiron/README.md
  • scripts/castiron/custom_code_report.py
  • scripts/castiron/test_custom_code_report.py
  • src/client.ts
  • src/resources/audio/transcriptions.ts
  • src/resources/audio/translations.ts
  • src/resources/beta/assistants.ts
  • src/resources/beta/beta.ts
  • src/resources/beta/index.ts
  • src/resources/beta/responses/internal-base.ts
  • src/resources/beta/responses/responses.ts
  • src/resources/beta/threads/index.ts
  • src/resources/beta/threads/runs/index.ts
  • src/resources/beta/threads/runs/runs.ts
  • src/resources/beta/threads/threads.ts
  • src/resources/chat/completions/completions.ts
  • src/resources/chat/completions/index.ts
  • src/resources/conversations/index.ts
  • src/resources/embeddings.ts
  • src/resources/files.ts
  • src/resources/fine-tuning/checkpoints/permissions.ts
  • src/resources/images.ts
  • src/resources/responses/internal-base.ts
  • src/resources/responses/responses.ts
  • src/resources/skills/skills.ts
  • src/resources/skills/versions/versions.ts
  • src/resources/vector-stores/file-batches.ts
  • src/resources/vector-stores/files.ts
  • src/resources/webhooks/index.ts
  • src/resources/webhooks/webhooks.ts
  • tests/lib/data-residency.test.ts

A changed generated baseline means this report cannot reliably identify which handwritten lines changed.

Inspect the custom-code diff

Download the exact patch produced by this run (requires repository access):

gh run download 33822316129 --repo openai/openai-node \
  --name castiron-custom-code-33822316129-1 --dir /tmp/castiron-custom-code-33822316129-1
git apply --stat /tmp/castiron-custom-code-33822316129-1/custom-code.patch
cat /tmp/castiron-custom-code-33822316129-1/custom-code.patch

Or reproduce it from an SDK checkout containing the vendored reporter:

git fetch --no-tags origin dde19c5c72280516fdfd4e0f4fe987fd1a3eced1 a9fcd2137fd1b8433673a914f85aab8494113b10
python3 scripts/castiron/custom_code_report.py report \
  --base dde19c5c72280516fdfd4e0f4fe987fd1a3eced1 \
  --head a9fcd2137fd1b8433673a914f85aab8494113b10 --fetch --require-head-hash --public \
  --out /tmp/castiron-custom-code-a9fcd2137fd1
cat /tmp/castiron-custom-code-a9fcd2137fd1/custom-code.patch

This is the current full custom patch for mixed files, not an attribution of only the handwritten lines changed by this PR.

Full report and patch

@HAYDEN-OAI
HAYDEN-OAI added this pull request to the merge queue Sep 4, 2026
@HAYDEN-OAI
HAYDEN-OAI removed this pull request from the merge queue due to a manual request Sep 4, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T00:23:12.194956Z 035d37e New commits
🔒 Security Review Completed 2026-09-04T00:23:28.982286Z 035d37e New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@HAYDEN-OAI
HAYDEN-OAI enabled auto-merge September 4, 2026 00:22
@HAYDEN-OAI
HAYDEN-OAI disabled auto-merge September 4, 2026 00:29
@HAYDEN-OAI
HAYDEN-OAI added this pull request to the merge queue Sep 4, 2026
Merged via the queue into openai:main with commit ce9d095 Sep 4, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants