Skip to content

fix(zod): report a misplaced boolean required instead of crashing - #3822

Open
luantaraschi wants to merge 2 commits into
orval-labs:masterfrom
luantaraschi:fix/report-misplaced-required
Open

fix(zod): report a misplaced boolean required instead of crashing#3822
luantaraschi wants to merge 2 commits into
orval-labs:masterfrom
luantaraschi:fix/report-misplaced-required

Conversation

@luantaraschi

@luantaraschi luantaraschi commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Implements option 2 from #3719, the one @snebjorn voted for and @melloware agreed with: report the invalid document rather than normalize it.

Reproduced first. A schema carrying required: true reaches the two spread sites in packages/zod/src/index.ts and fails with:

TypeError: (schema.required ?? []) is not iterable

That message names neither the schema nor what the keyword should hold, and generation of the whole client stops.

Both sites now read required through a small helper that returns the array when the document is valid and otherwise throws:

Invalid OpenAPI document: schema "Item" has `required: true`, but a schema
object's `required` must be an array of property names. A boolean `required`
belongs on the request body object or on a parameter, not on the schema it
references.

I did not normalize the value. A boolean carries no property names, so there is nothing to recover from it, and picking a set of required keys would change validation without the user knowing. That is the ambiguity @snebjorn raised.

Five tests, in packages/zod/src/zod.test.ts: the plain object path, the allOf path, the allOf member one level down, and two controls asserting a valid required array still generates, one on a schema and one on a member. Run against the commit before the fix, the first three fail and both controls pass on either side, so they are not asserting something that was already true. The three fail in two different ways, which is the point of the third one:

names the schema and the expected shape          got '(schema.required ?? []) is not iterable'
reports it on the allOf path too                got '(schema.required ?? []) is not iterable'
names the offending allOf member                expected [Function] to throw an error

The member one level down never threw at all. It rendered as zod.unknown() and said nothing.

packages/zod goes from 320 to 325 tests, all passing. tsc --noEmit and vp fmt --check are clean.

Scope note: packages/mock/src/faker/resolvers/value.ts spreads schemaReference.required the same way, so the same document shape would fail there too. I left it out to keep this focused on the reported path, and can send it separately if you want it covered.

Summary by CodeRabbit

  • Bug Fixes

    • Improved validation for schema required values.
    • Invalid non-array values now produce clear, descriptive errors identifying the affected schema.
    • Validation now works consistently across objects, combined schemas, and referenced schemas.
    • Valid required-field arrays continue to work correctly.
  • Tests

    • Added regression coverage for invalid and valid required configurations, including combined and referenced schemas.

A schema object's `required` is an array of property names, but some
generators put `required: true` on the schema a request body references,
borrowing the boolean that belongs on the request body object itself.
Spreading that boolean failed with

    (schema.required ?? []) is not iterable

which names neither the offending schema nor the expected shape, and
stopped generation of otherwise usable clients.

Both spread sites now read `required` through a helper that names the
schema and states what the keyword should contain. The document is not
rewritten: a boolean carries no property names, so there is nothing to
recover from it, and guessing would change validation silently.

Refs orval-labs#3719
Copilot AI lite review requested due to automatic review settings August 7, 2026 11:35

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The Zod package now validates schema-level required values through a shared helper. Direct object and allOf processing reject non-array values with descriptive errors. Regression tests cover invalid booleans and valid required-name arrays.

Changes

Required schema validation

Layer / File(s) Summary
Centralize required-value validation
packages/zod/src/index.ts
Added getRequiredKeys to accept arrays or omitted values and reject other types with a descriptive error.
Apply validation across schema processing
packages/zod/src/index.ts, packages/zod/src/zod.test.ts
AllOf and object-property required-key collection uses getRequiredKeys. Tests cover invalid boolean values, member-specific paths, and valid required arrays.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • orval-labs/orval#3719: Covers the same required: true failure in Zod schema and allOf/$ref processing.

Possibly related PRs

Suggested labels: bug

Suggested reviewers: snebjorn, melloware

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main fix for malformed boolean required values in Zod generation.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/zod/src/index.ts`:
- Line 786: Update the allOf resolution handling near getRequiredKeys so each
resolved member is validated with getRequiredKeys(resolved, name) when resolved
exists, rather than validating only the composing schema. Preserve the existing
behavior for unresolved members and add a regression test covering an allOf
constraint-only member with required: true, which must report the malformed
schema.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f5ffe00e-c519-488d-ba66-e45048f54fdb

📥 Commits

Reviewing files that changed from the base of the PR and between 457ef28 and d57feb2.

📒 Files selected for processing (2)
  • packages/zod/src/index.ts
  • packages/zod/src/zod.test.ts

Comment thread packages/zod/src/index.ts
@melloware melloware added the zod Zod schema client related issue label Aug 7, 2026
@melloware melloware added this to the 8.24.0 milestone Aug 7, 2026
@pkg-pr-new

pkg-pr-new Bot commented Aug 7, 2026

Copy link
Copy Markdown

Open in StackBlitz

@orval/angular

bun add https://pkg.pr.new/@orval/angular@cb11cbc

@orval/axios

bun add https://pkg.pr.new/@orval/axios@cb11cbc

@orval/core

bun add https://pkg.pr.new/@orval/core@cb11cbc

@orval/effect

bun add https://pkg.pr.new/@orval/effect@cb11cbc

@orval/fetch

bun add https://pkg.pr.new/@orval/fetch@cb11cbc

@orval/hono

bun add https://pkg.pr.new/@orval/hono@cb11cbc

@orval/mcp

bun add https://pkg.pr.new/@orval/mcp@cb11cbc

@orval/mock

bun add https://pkg.pr.new/@orval/mock@cb11cbc

orval

bun add https://pkg.pr.new/orval@cb11cbc

@orval/query

bun add https://pkg.pr.new/@orval/query@cb11cbc

@orval/solid-start

bun add https://pkg.pr.new/@orval/solid-start@cb11cbc

@orval/swr

bun add https://pkg.pr.new/@orval/swr@cb11cbc

@orval/zod

bun add https://pkg.pr.new/@orval/zod@cb11cbc

commit: cb11cbc

@melloware

Copy link
Copy Markdown
Collaborator

@snebjorn @wadakatu could use your eyes on this.

A constraint-only member has no properties, so it never reaches the object
path that validates `required`. Its `required` was read with
`Array.isArray`, which meant the same malformed keyword was reported on
the composing schema and ignored one level down.

The member is now read through the same helper. The label names the member
rather than the composing schema, because pointing at the parent sends the
reader to the wrong place in the document: an inline member reports as
`Parent.allOf[1]` and a `$ref` member reports as its ref.
@luantaraschi

Copy link
Copy Markdown
Contributor Author

The finding holds. I checked it before changing anything: with

{ allOf: [{ type: 'object', properties: { a: { type: 'string' } } }, { required: true }] }

generation completes today and the member renders as zod.unknown(). Nothing is lost, because a boolean carries no property names either way, but the document is malformed and the user hears nothing about it. Reporting it on the composing schema and ignoring it one level down was inconsistent, so I took the fix in cb11cbc.

One change from the proposed diff. It passes name, which is the composing schema's name, so a bad member would report as schema "Composed" has required: true and send the reader to a line that is fine. The member is labelled instead: an inline member reports as Composed.allOf[1], and a $ref member reports as its ref, since that is where the reader has to go to fix it.

Added two tests: the bad inline member, and a valid required: ['a'] on a member so the check does not swallow the legitimate case. The 289 tests in zod.test.ts pass.

@melloware melloware modified the milestones: 8.24.0, 8.25.0 Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

zod Zod schema client related issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(zod): crash on required: true sibling of a schema $ref(schema.required ?? []) is not iterable

4 participants