thibaultT
tRPC16mo ago
1 reply
thibault

Basic error handling patterns

Hello guys I am playing around with trpc and I don't know how to do error handling at a route level. I did read the docs about error handling but I don't know if my approach to this problem is good. How do you guys would handle errors in trpc ?

For example I have this sign up route. And the way I am doing error handling is by re throwing a TRPCError in the catch clause. Which doesn't seems right.

  signUp: publicProcedure
    .input(signUpSchema)
    .mutation(async ({ ctx, input }) => {
      try {
        // ... 

        // could throw on duplicate email.
        await ctx.db.insert(userTable).values(...);

        // ... 
      } catch (e) {
        if (isPgError(e) && e.constraint_name === "user_email_unique") {
          throw new TRPCError({
            code: "CONFLICT",
            message: "this email is already used",
          });
        }

        throw new TRPCError({
          code: "INTERNAL_SERVER_ERROR",
          message: e instanceof Error ? e.message : "unhandled error",
        });
      }
    }),


I also try to use the middleware approach but that doesn't work since trpc override the error constructor.

  signUp: publicProcedure
    .input(signUpSchema)
    .use(async ({ctx, next})=>{
      const res = await next();

      // does not work since the instance of res.error is no longer PostgresError but TRPCError
      if(!res.ok && isPgError(res.error) && res.error.constraint_name === "user_email_unique") {
        throw new TRPCError({
          code: "CONFLICT",
          message: "this email is already used",
        });
      }

      throw new TRPCError({
        code: "INTERNAL_SERVER_ERROR",
        message: res.error instanceof Error ? res.error.message : "unhandled error",
      });
    })
    .mutation(async ({ ctx, input }) => {
        // ... 

        // could throw on duplicate email.
        await ctx.db.insert(userTable).values(...);

        // ... 
    }),
Was this page helpful?