Describe the bug
I believe this is a bug, though I want to flag upfront that the staging in _handleSubmit seems to be intentional. Regardless I'd like to argue the current behavior still isn't right.
_handleSubmit runs validation in two stages with an early return between them:
await this.validateAllFields('submit') // Stage 1: field-level validators
if (!this.state.isFieldsValid){ /* ... */ return } // Gate
await this.validate('submit') // Stage 2: form-level validators
If Stage 1 fails, users only see the errors from this stage. So any other invalid fields stay silent until these errors are fixed. This contradicts what users intuitively expect from a submit action: check everything and show all errors.
Setting canSubmitWhenInvalid: true also doesn't fix this. The flag gates whether _handleSubmit runs at all, not how validation is staged within it.
My use case:
I only use form-level validation and canSubmitWhenInvalid: true.
Form-level validators write their errors into individual fields' errorMap. But isFieldsValid reads those entries without distinguishing source. So after a failed submit, those form-level errors count as "field-level invalid" on the next attempt — the isFieldsValid gate triggers, form-level validation is skipped, and stale errors stay on screen while new ones never appear.
This mechanism appears to be the underlying cause / relevant for several issues that have been reported separately: #1874, #1663 (see TeChn4K's reproduction there), #2034
PR #2120 in response to #2034 addresses a narrower symptom and doesn't solve the core issue: In #2034 the user has an onBlur validation on a field with conditional validation logic based on another field. The reported issue can be fixed by linking the other field with onBlurListenTo or using canSubmitWhenInvalid: true. The PR does not touch the isFieldsValid gate, so it does not address the problems above.
Your minimal, reproducible example
https://codesandbox.io/p/sandbox/tanstack-form-bug-7yxscz
Steps to reproduce
- Enter a value for field a, leave field b empty
- submit → Field b shows an error since it's empty
- clear field a
- submit again (notice
canSubmitWhenInvalid is set to true) → only field b shows an error even though field a is also empty
Expected behavior
On submit, both stages should run unconditionally and isValid should be evaluated once over the combined result:
await this.validateAllFields('submit')
await this.validate('submit')
if (!this.state.isValid) {
// onSubmitInvalid with the full error picture
return
}
// onSubmit
Why I think this is the right behavior:
- It matches user intuition for submit. Submit is the moment users most need a complete error report. Partial reports force them to fix-submit-fix-submit until they've discovered every problem, which is worse UX than showing everything at once.
- When
canSubmitWhenInvalid is false (the default), existing field errors already prevent _handleSubmit from running, so this change should have no effect unless there are filed level validators in which case all errors would now surface on submit instead of only the field-level ones, which I'd argue is also the right behavior. It changes behavior for forms that explicitly opt into canSubmitWhenInvalid: true — where a complete error report on every submit is exactly what you'd expect.
Happy to open a PR if there's a decision on this.
How often does this bug happen?
Every time
Screenshots or Videos
No response
Platform
not relevant
TanStack Form adapter
react-form
TanStack Form version
1.28.0
TypeScript version
No response
Additional context
No response
Describe the bug
I believe this is a bug, though I want to flag upfront that the staging in
_handleSubmitseems to be intentional. Regardless I'd like to argue the current behavior still isn't right._handleSubmitruns validation in two stages with an early return between them:If Stage 1 fails, users only see the errors from this stage. So any other invalid fields stay silent until these errors are fixed. This contradicts what users intuitively expect from a submit action: check everything and show all errors.
Setting
canSubmitWhenInvalid: truealso doesn't fix this. The flag gates whether_handleSubmitruns at all, not how validation is staged within it.My use case:
I only use form-level validation and
canSubmitWhenInvalid: true.Form-level validators write their errors into individual fields'
errorMap. ButisFieldsValidreads those entries without distinguishing source. So after a failed submit, those form-level errors count as "field-level invalid" on the next attempt — theisFieldsValidgate triggers, form-level validation is skipped, and stale errors stay on screen while new ones never appear.This mechanism appears to be the underlying cause / relevant for several issues that have been reported separately: #1874, #1663 (see TeChn4K's reproduction there), #2034
PR #2120 in response to #2034 addresses a narrower symptom and doesn't solve the core issue: In #2034 the user has an onBlur validation on a field with conditional validation logic based on another field. The reported issue can be fixed by linking the other field with onBlurListenTo or using
canSubmitWhenInvalid: true. The PR does not touch theisFieldsValidgate, so it does not address the problems above.Your minimal, reproducible example
https://codesandbox.io/p/sandbox/tanstack-form-bug-7yxscz
Steps to reproduce
canSubmitWhenInvalidis set to true) → only field b shows an error even though field a is also emptyExpected behavior
On submit, both stages should run unconditionally and
isValidshould be evaluated once over the combined result:Why I think this is the right behavior:
canSubmitWhenInvalidisfalse(the default), existing field errors already prevent_handleSubmitfrom running, so this change should have no effect unless there are filed level validators in which case all errors would now surface on submit instead of only the field-level ones, which I'd argue is also the right behavior. It changes behavior for forms that explicitly opt intocanSubmitWhenInvalid: true— where a complete error report on every submit is exactly what you'd expect.Happy to open a PR if there's a decision on this.
How often does this bug happen?
Every time
Screenshots or Videos
No response
Platform
not relevant
TanStack Form adapter
react-form
TanStack Form version
1.28.0
TypeScript version
No response
Additional context
No response