outis99
outis9913mo ago

Handling errors on the front-end

I'm making a mutation from my front-end and I intentionally throw a new TRPCError on my backend, I can see the trpc error on both client and server console but I don't understand how to catch it in the front-end The mutation onError does nothing, myMutation.isError is false, myMutation.error is null and status "idle" Here's some example code
const sendMessage = api.chatgpt.sendMessage.useMutation({
onError: (error) => {
console.log("error hit", error); //Doesn't execute
setLoadingResponse(false);
},
});
const sendMessage = api.chatgpt.sendMessage.useMutation({
onError: (error) => {
console.log("error hit", error); //Doesn't execute
setLoadingResponse(false);
},
});
And then on my code
sendMessage.mutate({ message: inputRef.current.value, chatId });
sendMessage.mutate({ message: inputRef.current.value, chatId });
How I throw the error
if (result.status === 200) { //Yes 200 is on purpose so I can test it
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "OpenAI API Error",
});
}
if (result.status === 200) { //Yes 200 is on purpose so I can test it
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "OpenAI API Error",
});
}
I also tried this
try {
sendMessage.mutate({ message: inputRef.current.value, chatId });
} catch (cause) {
if (isTRPCClientError(cause)) {
// `cause` is now typed as your router's `TRPCClientError`
// Nothing gets printed
console.log('data', cause.data);

}
}
try {
sendMessage.mutate({ message: inputRef.current.value, chatId });
} catch (cause) {
if (isTRPCClientError(cause)) {
// `cause` is now typed as your router's `TRPCClientError`
// Nothing gets printed
console.log('data', cause.data);

}
}
Pretty sure I'm just missing something here so a little help would be appreciated, thank you!
7 Replies
Nick
Nick13mo ago
If it’s not reaching the frontend then most likely your backend isn’t actually throwing the error, or some middleware is swallowing it Check the API-side onError and errorFormatter callbacks are receiving it
outis99
outis9913mo ago
I can see it on my frontend console
outis99
outis9913mo ago
Server-side onError receives it as well as the error formatter But as you can see on the image all the error values are false/null I looked through all the files but can't seem to find something that swallows it @nlucas
Nick
Nick13mo ago
Okay yeah it’s sending a 500 back so looks like that’s fine It looks like it should be calling the useMutation callback right now To catch imperatively you should await mutateAsync though
outis99
outis9913mo ago
Even that doesn't work, I'm sorry but I can't see what I am missing here and why throwing an error from the server is so difficult to handle on the client. All of the tRPC settings and files are default and I haven't changed any error formatters or loggerlinks or whatever, should I post a git issue for this maybe?
Dani;
Dani;13mo ago
Post your trpc & react-query instantiation code on the client
outis99
outis9913mo ago
On my _app.tsx export default api.withTRPC(MyApp); The api file
/**
* This is the client-side entrypoint for your tRPC API. It is used to create the `api` object which
* contains the Next.js App-wrapper, as well as your type-safe React Query hooks.
*
* We also create a few inference helpers for input and output types.
*/
import { httpBatchLink, loggerLink } from "@trpc/client";
import { createTRPCNext } from "@trpc/next";
import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server";
import superjson from "superjson";

import { type AppRouter } from "src/server/api/root";

const getBaseUrl = () => {
if (typeof window !== "undefined") return ""; // browser should use relative url
if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; // SSR should use vercel url
return `http://localhost:${process.env.PORT ?? 3000}`; // dev SSR should use localhost
};

/** A set of type-safe react-query hooks for your tRPC API. */
export const api = createTRPCNext<AppRouter>({
config() {
return {
/**
* Transformer used for data de-serialization from the server.
*
* @see https://trpc.io/docs/data-transformers
*/
transformer: superjson,

/**
* Links used to determine request flow from client to server.
*
* @see https://trpc.io/docs/links
*/
links: [
httpBatchLink({
url: `${getBaseUrl()}/api/trpc`,
}),
],
};
},
/**
* Whether tRPC should await queries when server rendering pages.
*
* @see https://trpc.io/docs/nextjs#ssr-boolean-default-false
*/
ssr: false,
});

/**
* Inference helper for inputs.
*
* @example type HelloInput = RouterInputs['example']['hello']
*/
export type RouterInputs = inferRouterInputs<AppRouter>;

/**
* Inference helper for outputs.
*
* @example type HelloOutput = RouterOutputs['example']['hello']
*/
export type RouterOutputs = inferRouterOutputs<AppRouter>;
/**
* This is the client-side entrypoint for your tRPC API. It is used to create the `api` object which
* contains the Next.js App-wrapper, as well as your type-safe React Query hooks.
*
* We also create a few inference helpers for input and output types.
*/
import { httpBatchLink, loggerLink } from "@trpc/client";
import { createTRPCNext } from "@trpc/next";
import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server";
import superjson from "superjson";

import { type AppRouter } from "src/server/api/root";

const getBaseUrl = () => {
if (typeof window !== "undefined") return ""; // browser should use relative url
if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; // SSR should use vercel url
return `http://localhost:${process.env.PORT ?? 3000}`; // dev SSR should use localhost
};

/** A set of type-safe react-query hooks for your tRPC API. */
export const api = createTRPCNext<AppRouter>({
config() {
return {
/**
* Transformer used for data de-serialization from the server.
*
* @see https://trpc.io/docs/data-transformers
*/
transformer: superjson,

/**
* Links used to determine request flow from client to server.
*
* @see https://trpc.io/docs/links
*/
links: [
httpBatchLink({
url: `${getBaseUrl()}/api/trpc`,
}),
],
};
},
/**
* Whether tRPC should await queries when server rendering pages.
*
* @see https://trpc.io/docs/nextjs#ssr-boolean-default-false
*/
ssr: false,
});

/**
* Inference helper for inputs.
*
* @example type HelloInput = RouterInputs['example']['hello']
*/
export type RouterInputs = inferRouterInputs<AppRouter>;

/**
* Inference helper for outputs.
*
* @example type HelloOutput = RouterOutputs['example']['hello']
*/
export type RouterOutputs = inferRouterOutputs<AppRouter>;
Also previously when I mentioned that settings are default I mean the default t3 stack configuration @s.daniel Let me know if you need anything else
More Posts
TypeScript Alias Imports don't get resolved ont the ClientI have a Monorepo with a multiple `/packages/*` packages, each has its own `tsconfig.json`. I noticmerging other routers to appRouterHey everyone, I am using the https://icflorescu.github.io/trpc-sveltekit package in my SvelteKit proCan I get non-redacted INTERNAL_SERVER_ERRORS in production?I'm trying to debug crashes in production, and having a hard time. As far as I can tell, errors are Error handling: Zod errors and manually thrown TRPCErrors have different shapeIf zod validation fails, the client-side `error.message` contains a JSON encoded array of errors, buprefetch() within getServerSideProps does not provide data upon manual refreshingWithin getServerSideProps: `await ssh.user.getDepositInfo.prefetch(userId);` `await ssh.user.getFQOHow to modify existing cache data?I have a message queue being fetched with InfiniteQuery requests. When adding a new message, I want When using createServerSideHelpers can the context be typed as GetServerSidePropsContext?I assume the reason we should recreate the context when using createServerSideHelpers is because theQuery data is undefined for a bit and is then populated. How to use with React State?I have an asychronous submit function that's called upon a button press. It refetches the query witshould we use tRPC for handling form submittion or not?Hey everyone, I've started using tRPC for my API endpoints and my project is based in Svelte/SvelteKWhat's the benefit of using the context instead of a direct import for the database connection?I've wondered why I should use the tRPC context instead of just importing my database singleton from