Skip to content

fix(form-core): ignore aborted async form-level validation results (continues #2350) - #2440

Open
AlexRixten wants to merge 2 commits into
TanStack:mainfrom
AlexRixten:fix/formapi-ignore-aborted-async-validation
Open

AlexRixten wants to merge 2 commits into
TanStack:mainfrom
AlexRixten:fix/formapi-ignore-aborted-async-validation

Conversation

@AlexRixten

@AlexRixten AlexRixten commented Oct 22, 2026 •

Copy link
Copy Markdown

🎯 Changes

Continues #2350 by @official-burak, which has been inactive since Aug 19 — all credit for the root-cause analysis, the fix, and the tests belongs there. This PR carries that work forward on current main so it can land.

Fixes #2346

FieldApi and FormGroupApi already drop in-flight async validation after a newer run aborts the previous AbortController. FormApi only checked the signal before starting the validator, not after it resolved.

That matters for form-level onChangeAsync validators that cannot observe the signal (including Standard Schema / Zod async refinements). A slower previous run can still apply its result and restore an error after a newer validation has already accepted the current value.

The check is the same one those sibling APIs already use: if controller.signal.aborted after the validator settles, resolve without writing errorMap.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested code changes locally with pnpm test:pr, or these tests do not apply to this pull request.
  • I fully understand the code in this pull request, including any code generated with AI assistance.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • Bug Fixes
    • Form-level asynchronous validation now ignores results from canceled validation runs. This prevents a slower, outdated result from adding errors or replacing the form’s state after a newer validation has completed.
    • Added regression coverage for the case where an invalid value is quickly replaced with a valid one, ensuring the earlier validation does not leave stale errors behind.

FieldApi and FormGroupApi already drop in-flight async results after a newer run aborts them. FormApi was missing that check, so a slower previous validator could overwrite newer valid state.
@changeset-bot

changeset-bot Bot commented Oct 22, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 120e211

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 14 packages
Name Type
@tanstack/form-core Patch
@tanstack/angular-form Patch
@tanstack/form-devtools Patch
@tanstack/lit-form Patch
@tanstack/preact-form Patch
@tanstack/react-form Patch
@tanstack/solid-form Patch
@tanstack/svelte-form Patch
@tanstack/vue-form Patch
@tanstack/react-form-devtools Patch
@tanstack/solid-form-devtools Patch
@tanstack/react-form-nextjs Patch
@tanstack/react-form-remix Patch
@tanstack/react-form-start Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Source mode: Auto
  • Repository: TanStack/form
  • Branch: main
  • File: .coderabbit.yaml
  • Commit: 2216fde
  • Layers: Repository YAML
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fe8d0da8-390e-4dfb-8639-cd79efb4581d
📥 Commits

Reviewing files that changed from the base of the PR and between 2216fde and 120e211.

📒 Files selected for processing: 3
  • .changeset/quiet-forms-ignore-stale.md
  • packages/form-core/src/FormApi.ts
  • packages/form-core/tests/FormApi.spec.ts

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.

📝 Walkthrough

Form-level asynchronous validation now ignores a validator result or error if its abort signal is canceled. A regression test checks that an earlier, slower invalid result does not add errors after a later valid result completes.

Changes: Form-level async validation

Layer / File(s) Summary
Ignore canceled validation results
packages/form-core/src/FormApi.ts, packages/form-core/tests/FormApi.spec.ts, .changeset/quiet-forms-ignore-stale.md
validateAsync resolves canceled validator results or errors with undefined before error normalization or state updates. The regression test checks form errors and errorMap.onChange after slow-invalid and valid validations complete. The changeset records a patch for @tanstack/form-core.

Priority: ➖ Normal

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

Change: Bug fix · Severity of issue fixed: Low

Merge Risk: ⚪ Minimal · up to 120e2

The change prevents an older canceled validation result from adding stale form errors. No actionable risk introduced by this PR remains after normal checks.

Pre-merge checks: Passed 5
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: ignoring aborted asynchronous form-level validation results.
Description check Passed The description explains the motivation, implementation, affected APIs, linked issues, test coverage, and release impact. It includes all required template sections and completed checklist items.
Linked Issues check Passed The PR addresses #2346. The supplied change summary states that FormApi.validateAsync checks the abort signal after an async validator resolves or rejects and returns undefined before it normalize…
Out of Scope Changes check Passed The changed files have a direct connection to #2346. FormApi.ts contains the cancellation guard. FormApi.spec.ts adds the related regression test. The changeset documents the published behavior ch…
Docstring Coverage Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2…
Full details: Linked Issues check

Explanation

The PR addresses #2346. The supplied change summary states that FormApi.validateAsync checks the abort signal after an async validator resolves or rejects and returns undefined before it normalizes or writes errors. The regression test covers a slow invalid value followed by a valid value and verifies that the older result does not populate form errors or errorMap.onChange. The changeset documents the same fix for @tanstack/form-core.

Full details: Out of Scope Changes check

Explanation

The changed files have a direct connection to #2346. FormApi.ts contains the cancellation guard. FormApi.spec.ts adds the related regression test. The changeset documents the published behavior change. No unrelated change is identified in the supplied PR evidence.

Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2 files. (1 skipped: 1 unsupported.)

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

This branch has not been deployed

No deployments
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.

Aborted async Standard Schema validation can overwrite newer form state

2 participants