What to use when the Backend returns a form error? Validator vs Submit
Hi!
So I have a form that has
onSubmit
validators. They are there so we do basic validations (through zod) like numbers, minimum characters, etc.
I also have a regular onSubmit
prop where I call the backend if the validator checks that everything is okay.
Now, the Backend may return errors as well, such as Username already exists
, but it does so when we actually try to create the user - there isn't a separate service where I check for usernames. Basically the POST to /api/users returns a 400
with the error message.
I have checked this example -> https://tanstack.com/form/latest/docs/framework/react/examples/field-errors-from-form-validators but here there isn't an onSubmit
handler, just a validator. Also, I think it assumes there is a service specifically for checking if the username already exists (which isn't my case)
My question is: In my case I feel like I should still call the CreateUser service inside the onSubmit
because the validator shouldn't be the one creating users when the form is all okay.
How would you approach this? And also, how would you highlight the username field like on the example, when there's an error OUTSIDE a validator
(inside a regular onSubmit
), like this?:
Thanks in advance!React TanStack Form Field Errors From Form Validators Example | Tan...
An example showing how to implement Field Errors From Form Validators in React using TanStack Form.
42 Replies
rising-crimson•22h ago
because the validator shouldn't be the one creating users when the form is all okayThat's the thing though - You have no separation of concerns here. If there are no validation errors, then the change has already happened, and if there were, then the change wasn't saved in the database. In the current implementation of
onSubmit
, only successful forms should go through. Only endpoints that are not validators should be called in it.
If you have an endpoint that returns validation errors, you should use it in validators.onSubmitAsync
. It is only called on submit, and only runs if validators.onSubmit
has passed successfully.
That being said - While we can talk all day about how this makes logical sense or not, it doesn't feel right. So we'll add a way to create validation errors in onSubmit
sometime in the future. For now, you'll have to do with the code mentioned above.sensitive-blueOP•21h ago
Thank you so much Luca! So your suggestion for now would be for me to ditch the
onSubmit
and instead use validators.onSubmit
along with validators.onSubmitAsync
, so I can react to errors, right?
Thanks again! 🙏rising-crimson•21h ago
yeah. That basically sums it up
How you approached it before:
* Validators in
validators
* Validators should not mutate data
* Validators return user errors
* onSubmit
should mutate data
* onSubmit
returns transient errors and user errors
How TSF sees it (for now):
* Validators in validators
* Validators should be async, the result should determine if it had errors or not
* Validators return user errors
* onSubmit
can mutate data
* onSubmit
is only for successful submissions
* onSubmit
returns transient errorssensitive-blueOP•21h ago
Gotcha, thanks a lot, I’ll keep an eye on the news ❤️
rising-crimson•21h ago
Sounds good! Let me know if you have other questions
sensitive-blueOP•20h ago
I actually have one more question now @Luca | LeCarbonator:
This approach now seems to break the form composition pattern, when we pass the form (type errors). I have created a small StackBlitz example so you can check it, maybe I'm missing something:
https://stackblitz.com/edit/validator-onsubmitasync-composable?file=src%2Findex.tsx (check line 67 on index.tsx)
seab
StackBlitz
validator.onSubmitAsync with Composable sections - StackBlitz
Run official live example code for Form Field Errors From Form Validators, created by Tanstack on StackBlitz
sensitive-blueOP•20h ago
For reference:

rising-crimson•20h ago
the error happens because
withForm
expects a form with a specific shape. That way, you can still get the errors in a type safe way inside withForm
.
However, that also means that your endpoint now caused a difference between what withForm
expects and what your state
will end up as
so withForm
expects to know what validators are present and what types they have. The actual runtime value of those validators won't matter for withForm
as they are unusedsensitive-blueOP•20h ago
Hmm I see. So what would be the best approach here? Is it safe to ignore these errors? They always show up as soon as I use any
validators.onSubmitAsync
, regardless of their contentrising-crimson•20h ago
the best approach would be to ensure
withForm
knows about the validator.
In the current setup, form.state.errorMap.onSubmit
is not the same type between the form in withForm
vs. the form you're actually using
so in this case, add this to withForm
:
sensitive-blueOP•20h ago
That makes sense, but it doesn't seem to solve my issue :/ I'm not sure what to do next

rising-crimson•19h ago
oh, I thought it resolved the issue in my fork. One sec
no error is thrown if I open your stackblitz. Are you sure it's not fixed?
sensitive-blueOP•19h ago
What browser are you using? It doesn't show any error on FF, but it does on Brave 🤔 On my local environment, on my real app, this error always occurs
rising-crimson•19h ago
FF
wouldn't be the first time that stackblitz has inconsistencies like that.
can you copy the last few lines of the error and share them here? The ones you get on Brave
sensitive-blueOP•19h ago
So this is the type error I get, part 1:
And part 2:
rising-crimson•19h ago
hm, looks like it's because one's async and the other one isn't
sensitive-blueOP•19h ago
I've also tried that, without success 🙁
rising-crimson•19h ago
if only this error showed up for me :Madge: let me try chrome
looks like it doesn't show up on chrome either. I'll copy the code and check locally
sensitive-blueOP•19h ago
I'm sorry for making you open that crap 😹
thank you so much in advance 🙏
rising-crimson•19h ago
free chance to get more feedback
in this case, reasons to add
createError
to onSubmit
what the ... it's because of different argument size?sensitive-blueOP•19h ago
whaaat?
rising-crimson•19h ago
Okay, it looks like it's really really really really strict. More than I thought it initially was.
I'll write something up in a moment, just need to check some things
rising-crimson•19h ago
in the meantime, I can recommend this VSCode extension if you use it
https://marketplace.visualstudio.com/items?itemName=yoavbls.pretty-ts-errors
Pretty TypeScript Errors - Visual Studio Marketplace
Extension for Visual Studio Code - Make TypeScript errors prettier and more human-readable in VSCode
rising-crimson•19h ago
not for this error, just in general. I really like the extension
sensitive-blueOP•19h ago
Oh yeah, I love it! Unfortunately StackBlitz doesn't have it 😭
rising-crimson•19h ago
Yeah, unfortunately. Anyways, I was able to recreate the error.
It was so specific that it even knew which fields you assigned errors to. Not that I expected it, but annoying for cases like this.
If you use the latest version, there's something I can recommend instead. If you want to split up your form into multiple components (with
withForm
), you can extract the common fields and their types using formOptions
:
What this will do is make sharing between form sections way easier.
This would be very convenient if you used schemas or the like, but in your case, that includes the endpoint ...
The main things that withForm
and useAppForm
must have in common is defaultValues and validators. listeners can still be placed in useAppForm
without problem
-# and also maybe because they're broken in formOptions at the moment
A smaller feature I've been thinking of is giving a handy function to create field-level errors from a form.
Since it's not in the library (but possible), here's the snippet. Maybe it helps with type safety and broadening the type more so you encounter less of these hyper-specific errors:
sensitive-blueOP•19h ago
Wooow, thanks for all the information! I'd loooove this feature! How would you manually clear up these custom errors, when using that snippet?
rising-crimson•19h ago
manually clear up?
could you elaborate'
sensitive-blueOP•19h ago
Let's say I called
createFieldLevelError
with an error on an input field. Then the user changes the input. Does the error persist? Or would I need to call something like clearFieldLevelError
on it?rising-crimson•19h ago
depends on the validator you used
everything apart from onSubmit is considered persistent, so you need to have another call that clears the error in question.
onSubmit errors get cleared if the field changes its value
sensitive-blueOP•19h ago
oh so it would work together with the onChange, onSubmit, etc handlers? that's incredible
rising-crimson•19h ago
yeah, the function above works for any form-level validator
and the form already knows TData, which is why it should be exported (or at least passed to the validators callback)
sensitive-blueOP•19h ago
Peeerfect!
Thank you so much for your help ❤️
rising-crimson•19h ago
no worries 👍
sensitive-blueOP•19h ago
Btw I had used the formOptions functions, but I thought only the defaultValues would make sense to share between form composition components. I was like: "why the hell would the
<Fields />
component be aware of the onSubmit
handler, or validators for other areas of the form?
But from what I understood, it's not harmful to include everything, right? Even if my validators.onSubmitAsync
is also present inside <Fields />rising-crimson•19h ago
well, that feature was introduced right as I started working with the library, so I don't really know why it was added
I personally don't mind structured errors being returned, but to each their own
yeah, in
withForm
, it's only for typing help
no runtime stuff
in withFieldGroup
, the only thing that ends up being used is the Object.keys(defaultValues)
. It's needed so you can map form fields and the like
the rest is also unusedsensitive-blueOP•19h ago
I see I see, I had no idea at all. It honestly seems kinda weird, but I'm glad I understood it now
rising-crimson•19h ago
it's common for higher order components. But you don't see them around that much anymore
sensitive-blueOP•19h ago
Yup, I never seem them now. Are there any plans to change
withForm
from HOC to something else?rising-crimson•19h ago
hard to say. I doubt form composition will receive much of an overhaul in a v2. There's a bunch of things to address when it comes to validation though, so maybe that will indirectly affect it
either way that's a long way away
sensitive-blueOP•19h ago
Gotcha. Again, thanks a lot and amazing work with the library, have a nice day 😄
rising-crimson•19h ago
you too ❤️