Skip to content

fix(schema): prevent crash validating unions of object arrays - #1638

Merged
ssalbdivad merged 1 commit into
arktypeio:mainfrom
xianjianlf2:fix/array-union-in-operator-crash-1458
Sep 18, 2026
Merged

ssalbdivad merged 1 commit into
arktypeio:mainfrom
xianjianlf2:fix/array-union-in-operator-crash-1458

Conversation

@xianjianlf2

Copy link
Copy Markdown
Contributor

Problem

When a union of array types with object element bases (e.g. { objB: string }[] | { objC: string }[]) was validated against an array containing a non-object element, a TypeError: Cannot use 'in' operator was thrown.

Inside a union branch, traversal runs in fail-fast mode and ctx.currentErrorCount saturates at 1, so an intersection's basis (object/proto) failure guard (currentErrorCount > errorCount) could not detect a newly added error once an earlier element in the same branch had already errored. The sequence node then continued iterating and applied the element's structure check (key in data) to a primitive, throwing.

Fix

SequenceNode now mirrors StructureNode by bailing out of remaining elements in fail-fast mode, both in traverseApply and in its compiled output, so a failed element basis short-circuits before the unguarded in check runs. Top-level (non-fail-fast) validation is unchanged and still collects every element error.

Testing

Added a regression test in ark/type/__tests__/union.test.ts covering a union of object arrays validated against an array containing a non-object element, confirming it no longer throws and reports a proper validation error.

Closes #1458

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes — this PR prevents a hard TypeError crash when validating a union of object arrays against an array containing a primitive element, by making SequenceNode bail out of further element traversal in fail-fast mode (e.g. inside a union branch), matching the behavior already implemented in StructureNode.

  • SequenceNode.traverseApply now checks ctx.failFast && ctx.currentErrorCount > errorCount after each element and returns early, stopping traversal of later elements once one element has failed inside a fail-fast context.
  • SequenceNode.compile now initializes an errorCount snapshot and emits js.returnIfFailFast() after each prefix, defaultable/optional, variadic, and postfix element in the generated Apply traversal, producing the compiled equivalent of the runtime short-circuit.
  • Regression test added to ark/type/__tests__/union.test.ts covering both element-orderings from issue #1458.

Pullfrog  | View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

When a union of array types with object element bases (e.g.
`{ objB: string }[] | { objC: string }[]`) was validated against an
array containing a non-object element, a `TypeError: Cannot use 'in'
operator` was thrown.

Inside a union branch, traversal runs in fail-fast mode and
`ctx.currentErrorCount` saturates at 1, so an intersection's basis
(object/proto) failure guard (`currentErrorCount > errorCount`) could
not detect a newly added error once an earlier element in the same
branch had already errored. The sequence node then continued iterating
and applied the element's structure check (`key in data`) to a
primitive, throwing.

SequenceNode now mirrors StructureNode by bailing out of remaining
elements in fail-fast mode, both in `traverseApply` and in its compiled
output, so a failed element basis short-circuits before the unguarded
`in` check runs. Top-level (non-fail-fast) validation is unchanged and
still collects every element error.

Closes arktypeio#1458
@ssalbdivad
ssalbdivad force-pushed the fix/array-union-in-operator-crash-1458 branch from 2f6a097 to 788981b Compare September 18, 2026 18:36
@ssalbdivad
ssalbdivad merged commit d66d8d2 into arktypeio:main Sep 18, 2026
6 checks passed
@github-project-automation github-project-automation Bot moved this from To do to Done (merged or closed) in arktypeio Sep 18, 2026
@ssalbdivad

Copy link
Copy Markdown
Member

@xianjianlf2 thanks so much great find and the fix is perfect!

@ssalbdivad ssalbdivad mentioned this pull request Sep 24, 2026
4 tasks done
ssalbdivad added a commit that referenced this pull request Sep 24, 2026
Bumps all publishable packages and documents the changes merged since 2.2.4:

- preserve escaped backslashes in regex literals (#1634, @spokodev)
- fix recursive discriminated unions referenced from a Record (#1641, @xianjianlf2)
- prevent a crash validating unions of object arrays (#1638, @xianjianlf2)
- merge index-derived props with a declared key of the same name (#1659)
- preserve parameter labels when a type.fn implementation annotates an
  optional param (#1615, @aswinsvijay)

#1634 changes behavior for regex literals that contain `\\`: `"/\\\\d/"`
previously compiled to the digit class `\d` and now matches a literal
backslash followed by "d", matching the equivalent RegExp instance. The
changelog calls this out with a migration note.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done (merged or closed)

Development

Successfully merging this pull request may close these issues.

Array union TypeError

2 participants