When to use
- Next.js Server Actions feed TanStack Query mutations.
- Expected action failures need toast or inline UI.
- Production error messages are sanitized.
throwOnError,QueryBoundary, or error codes are involved.
Goal
Do not throw expected user-facing errors from Server Actions. Return typed failure data. Throw only inside the client mutation when React Query needs an error.
Rules
- Return
ActionResult<T, E>from Server Actions. - Map raw server or API failures to safe error codes.
- Keep raw backend errors server-side.
- Translate error codes on the client.
- Throw a normal client-side
ErrorfrommutationFnfor expected failures. - Handle mutation errors close to the mutation or workflow.
- Do not set global mutation
throwOnError: true. - Use mutation-level
throwOnError: trueonly for boundary fallback UI.
Result Type
export type ActionResult<T, E> =
| { success: true; data: T }
| { success: false; error: E };
Flow
- Server Action returns
ActionResult<T, ErrorCode>. - Server maps raw failures to typed error codes.
mutationFncalls action.- If
success, returndata. - If failure, throw client-side translated
Error. onErrorshows toast or updates UI.- Use
throwOnError: trueonly for boundary fallback.
Pattern
const mutation = useMutation({
mutationFn: async (input: Input) => {
const result = await action(input);
if (result.success) return result.data;
throw new Error(t(`errors.${result.error}`));
},
onError: (error) => toast.error(error.message),
});
Avoid
- Throwing expected Server Action errors for toast messages.
- Reading production Server Action
Error.messageon the client. - Returning raw backend errors to the browser.
- Catching and exposing all thrown server errors.
- Duplicating message strings across action and client.
Output
- Typed action result.
- Safe error code enum or union.
- Client-side unwrap in
mutationFn. - Local
onErrorhandling.