ivan
ivan2mo ago

How to map internal errors to TRPCError types?

Hi, my application is throwing it's own set of custom Errors. Unfortunatelly tRPC always catch this errors and represent them as UNEXPECTED_SERVER_ERROR type. I tried following:
t.procedure.use(async ({ next }) => {
const result = await next();

if (result.ok) return result;

// error is already TRPCError
result.error
})
t.procedure.use(async ({ next }) => {
const result = await next();

if (result.ok) return result;

// error is already TRPCError
result.error
})
I ended up wrapping all of my mutation/query handlers in following function:
export const appRouter = t.router({
settingsUpdate: t.procedure.mutation(async () => transformErrors(() => myHandler())
});

async function transformErrors<T>(handler: () => Promise<T>) {
try {
return await handler();
} catch (error) {
if (error instanceof TRPCError) throw error;
if (error instanceof BadRequestError)
throw new TRPCError({
code: "BAD_REQUEST",
message: error.message,
});
if (error instanceof NotFoundError)
throw new TRPCError({
code: "NOT_FOUND",
message: error.message,
});
if (error instanceof ForbiddenError)
throw new TRPCError({
code: "FORBIDDEN",
message: error.message,
});
if (error instanceof UnauthorizedError)
throw new TRPCError({
code: "UNAUTHORIZED",
message: error.message,
});

console.error(error);

throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
});
}
}
export const appRouter = t.router({
settingsUpdate: t.procedure.mutation(async () => transformErrors(() => myHandler())
});

async function transformErrors<T>(handler: () => Promise<T>) {
try {
return await handler();
} catch (error) {
if (error instanceof TRPCError) throw error;
if (error instanceof BadRequestError)
throw new TRPCError({
code: "BAD_REQUEST",
message: error.message,
});
if (error instanceof NotFoundError)
throw new TRPCError({
code: "NOT_FOUND",
message: error.message,
});
if (error instanceof ForbiddenError)
throw new TRPCError({
code: "FORBIDDEN",
message: error.message,
});
if (error instanceof UnauthorizedError)
throw new TRPCError({
code: "UNAUTHORIZED",
message: error.message,
});

console.error(error);

throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
});
}
}
I just wanted to ask if there isn't better way of doing this - eg. I believe this is exactly what middleware is supposed to do - apply code per each handler so you don't need to. How can I get anything else than TRPCError in middleware?
1 Reply
Nick
Nick2mo ago
So tRPC has errorFormatter which you can use globally Otherwise throwing tRPC errors at the procedure level is good when you want to include a specific status code For handling errors in the client using the errorFormatter is good because its type-safe though you don’t need to worry about the status code so much since it’s just typescript

Did you find this page helpful?