T
TanStack4mo ago
fascinating-indigo

Generic type for onServer value in setErrorMap remains undefined

We started using the lib in NextJS 15 at version 1.3. Currently trying to update to the latest (1.11.3), but it's giving me a typescript issue on one location. Diving a bit deeper into this, everything worked fine up untill 1.8, from 1.9 onward this breaks. We have quite an abstract implementation with createFormHook and createFormHookContexts. For the onSubmit validation we have written a solution that ensures both client side as well as server side errors correctly get passed through to the client form.
const form = useForm({
validators: {
onBlur: TestActionSchema,
},
defaultValues: {
username: "",
password: "",
age: 22,
} as TestActionSchemaType,
onSubmit: async ({ value, formApi }) => {
const result = await testAction(value);

if (!result.success) {
/* Setting server validation field errors */
if (result.formErrors) {
for (const [key, errors] of Object.entries(result.formErrors)) {
formApi.setFieldMeta(key as any, (prev) => ({
...prev,
errorMap: {
onSubmit: errors ? errors.map((error: string) => ({ message: error })) : undefined,
},
}));
}
return;
}

/* Setting server error that is accessible from form */
if (result.serverError) {
formApi.setErrorMap({
onServer: [result.serverError],
});
return;
}
}

if (result.success) {
form.reset();
}
},
});
const form = useForm({
validators: {
onBlur: TestActionSchema,
},
defaultValues: {
username: "",
password: "",
age: 22,
} as TestActionSchemaType,
onSubmit: async ({ value, formApi }) => {
const result = await testAction(value);

if (!result.success) {
/* Setting server validation field errors */
if (result.formErrors) {
for (const [key, errors] of Object.entries(result.formErrors)) {
formApi.setFieldMeta(key as any, (prev) => ({
...prev,
errorMap: {
onSubmit: errors ? errors.map((error: string) => ({ message: error })) : undefined,
},
}));
}
return;
}

/* Setting server error that is accessible from form */
if (result.serverError) {
formApi.setErrorMap({
onServer: [result.serverError],
});
return;
}
}

if (result.success) {
form.reset();
}
},
});
It seems like TOnServer never gets set? I'm however not sure what's needed in order for typescript to know what the type is for TOnServer
No description
9 Replies
fascinating-indigo
fascinating-indigoOP4mo ago
Forgot to mention, the code itself works just like before, it's just the type that is giving me issues :blbsmilesweat2:
flat-fuchsia
flat-fuchsia4mo ago
your validators don‘t specify a onServer, so typescript tries to prevent you from setting an error in a location where it doesn‘t expect any if it‘s validation-related functions in onSubmit, consider moving them into the onSubmitAsync validator instead
fascinating-indigo
fascinating-indigoOP4mo ago
Thanks for replying! We want to ensure any server side error can be communicated to the client via serverError. This means that it is not always a form validation error. Just tried out adding onError in validators, but it doesn't exist :S
flat-fuchsia
flat-fuchsia4mo ago
there‘s onSubmitInvalid, maybe that could help?
fascinating-indigo
fascinating-indigoOP4mo ago
That doesn't get triggered. Problem is, the client side submit is valid, so the server action gets triggered. This server action then throws an error because something else is off. So this is before the submit (on the left - as you can see no errors). And after the submit (on the right, with a visual FormError) To debug we programmed the server action to throw an error on the server if the username is set to 'server-error'
No description
No description
flat-fuchsia
flat-fuchsia4mo ago
so the server error is still validation-related, right? Errors like „username is taken“? I‘m not sure I follow why it wouldn‘t be a form validation error If it‘s a general error, then it would belong to external state if it was successful, then it would not return an error and simply continue to the onSubmit callback
fascinating-indigo
fascinating-indigoOP4mo ago
First of all just want to say sorry and that me and my team are having a hard time grasping the correct flow of Tanstack Form in combination with NextJS as we're all new to server components and what not :kek: We previously only worked with SPA, so it's been quite a journey to get the correct mindset around SSR. If the server error is field related then it's indeed a validation error. It's however possible that the server action breaks on something else entirely in the backend, but I'm guessing you see that as a general error then? How would you go about it then to parse any error from the backend to the external state?
flat-fuchsia
flat-fuchsia4mo ago
a simple usestate. If the backend errors, the user had nothing to do with it and does not need to „fix“ anthing. Therefore, it should be external so that the user can see it, but is still allowed to submit However, if the error is indeed validation, then the user must fix a field also no worries! I may sound harsh, but that‘s because I‘m on the phone and typing long sentences is difficult.
fascinating-indigo
fascinating-indigoOP4mo ago
Haha nah I merely said that out of personal frustration 🙈 So after your comment I explored the validators a bit more, wrote a solution for validator.onSubmit where it's clear what the return format of the errors should be {form: ..., fields: ...}. This worked fine, but resulted in some code duplication that we preferred not to have. Then I figured I might be able to use the same format for the setErrorMap onSubmit, which ended up being a correct conclusion 🙂 So by changing this code
formApi.setErrorMap({
onServer: [result.serverError],
});
formApi.setErrorMap({
onServer: [result.serverError],
});
To this
formApi.setErrorMap({
onSubmit: {form: [result.serverError], fields: {}},
});
formApi.setErrorMap({
onSubmit: {form: [result.serverError], fields: {}},
});
My problems are solved 😄 Still wondering why/how I could've gotten the onServer variant working, but I can't figure out how to let the TS inference know onServer is a thing. Maybe it's a bug... but at least my issue is fixed and we're up to date now with the latest version.

Did you find this page helpful?