From 529ca159f78b0ae1bffe0a75d3e27adee1cee2a4 Mon Sep 17 00:00:00 2001 From: Benny Joo Date: Wed, 10 Dec 2025 04:21:55 +0900 Subject: [PATCH] refactor: remove TRPCError handling from getServerErrorFromUnknown (#25691) * refactor: remove TRPCError handling from getServerErrorFromUnknown This removes the @trpc/server dependency from packages/lib by removing TRPCError handling from getServerErrorFromUnknown.ts. packages/lib is meant to be a general utility library that other packages depend on, so it shouldn't import tRPC. The callers that need to handle TRPCError (like onErrorHandler.ts and defaultResponder.ts) already handle it explicitly before calling getServerErrorFromUnknown, so this change has no behavioral impact. Changes: - Remove TRPCError and getHTTPStatusCodeFromError imports - Remove TRPCError instanceof check from getServerErrorFromUnknown - Update docstring to note that TRPCError is not handled - Remove TRPCError-related tests (they belong in the tRPC layer) - Fix lint warnings in Prisma error tests (replace 'as any' with proper type) Co-Authored-By: benny@cal.com * wip --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- packages/lib/eslint.config.mjs | 23 +++++++++++ .../server/getServerErrorFromUnknown.test.ts | 40 +------------------ .../lib/server/getServerErrorFromUnknown.ts | 17 ++------ 3 files changed, 28 insertions(+), 52 deletions(-) diff --git a/packages/lib/eslint.config.mjs b/packages/lib/eslint.config.mjs index c47ff3ffed..b874c6454c 100644 --- a/packages/lib/eslint.config.mjs +++ b/packages/lib/eslint.config.mjs @@ -13,4 +13,27 @@ export default [ target: ".", message: "lib package should not import from features to avoid circular dependencies.", }), + forbid({ + from: "../trpc/**", + target: ".", + message: "lib package should not import from trpc to avoid circular dependencies.", + }), + { + // Block @trpc/server imports to keep packages/lib framework-agnostic. + // defaultResponder.ts is temporarily excluded until it can be refactored. + ignores: ["server/defaultResponder.ts", "server/defaultResponder.test.ts"], + rules: { + "no-restricted-imports": [ + "error", + { + paths: [ + { + name: "@trpc/server", + message: "packages/lib should not import from @trpc/server to keep it framework-agnostic.", + }, + ], + }, + ], + }, + }, ]; diff --git a/packages/lib/server/getServerErrorFromUnknown.test.ts b/packages/lib/server/getServerErrorFromUnknown.test.ts index b922312b0b..692194ca77 100644 --- a/packages/lib/server/getServerErrorFromUnknown.test.ts +++ b/packages/lib/server/getServerErrorFromUnknown.test.ts @@ -1,11 +1,9 @@ -import { Prisma } from "@calcom/prisma/client"; import { describe, expect, test } from "vitest"; import { ZodError } from "zod"; import { ErrorCode } from "@calcom/lib/errorCodes"; import { ErrorWithCode } from "@calcom/lib/errors"; - -import { TRPCError } from "@trpc/server"; +import { Prisma } from "@calcom/prisma/client"; import { HttpError } from "../http-error"; import { TracedError } from "../tracing/error"; @@ -156,42 +154,6 @@ describe("TracedError handling", () => { }); }); -describe("TRPCError handling", () => { - test("should handle TRPCError with BAD_REQUEST", () => { - const trpcError = new TRPCError({ - code: "BAD_REQUEST", - message: "Invalid input data", - }); - - const result = getServerErrorFromUnknown(trpcError); - - expect(result.statusCode).toBe(400); - expect(result.message).toBe("Invalid input data"); - expect(result.data).toBeUndefined(); - }); - - test("should handle TracedError wrapping TRPCError", () => { - const trpcError = new TRPCError({ - code: "NOT_FOUND", - message: "Resource not found", - }); - const tracedData = { resourceId: "789" }; - const traceContext = { - traceId: "trace_trpc123", - spanId: "span_trpc123", - operation: "resource_lookup", - }; - - const tracedError = new TracedError(trpcError, traceContext, tracedData); - - const result = getServerErrorFromUnknown(tracedError); - - expect(result.statusCode).toBe(404); - expect(result.message).toBe("Resource not found"); - expect(result.data).toEqual({ ...tracedData, traceId: traceContext.traceId }); - }); -}); - describe("ZodError handling", () => { test("should handle ZodError with validation issues", () => { const zodError = new ZodError([ diff --git a/packages/lib/server/getServerErrorFromUnknown.ts b/packages/lib/server/getServerErrorFromUnknown.ts index 41ba8e0451..36ed769be4 100644 --- a/packages/lib/server/getServerErrorFromUnknown.ts +++ b/packages/lib/server/getServerErrorFromUnknown.ts @@ -5,9 +5,6 @@ import { ErrorCode } from "@calcom/lib/errorCodes"; import { ErrorWithCode } from "@calcom/lib/errors"; import { Prisma } from "@calcom/prisma/client"; -import { TRPCError } from "@trpc/server"; -import { getHTTPStatusCodeFromError } from "@trpc/server/http"; - import { HttpError } from "../http-error"; import { redactError } from "../redactError"; import { stripeInvalidRequestErrorSchema } from "../stripe-error"; @@ -40,8 +37,11 @@ function parseZodErrorIssues(issues: ZodIssue[]): string { /** * Converts unknown error types to HttpError with proper status code mapping and error redaction. * SERVER-ONLY: This function imports Prisma and Stripe schemas and should only be used in server-side code. - * Use in API routes, tRPC handlers, webhooks, and server-side services. + * Use in API routes, webhooks, and server-side services. * For client-side code, use getErrorFromUnknown from @calcom/lib/errors instead. + * + * NOTE: This function does NOT handle TRPCError. Callers that need to handle TRPCError should do so + * explicitly before calling this function (see onErrorHandler.ts and defaultResponder.ts for examples). */ export function getServerErrorFromUnknown(cause: unknown): HttpError { let traceId: string | undefined; @@ -53,15 +53,6 @@ export function getServerErrorFromUnknown(cause: unknown): HttpError { cause = cause.originalError; } - if (cause instanceof TRPCError) { - const statusCode = getHTTPStatusCodeFromError(cause); - return new HttpError({ - statusCode, - message: cause.message, - cause, - data: traceId ? { ...tracedData, traceId } : undefined, - }); - } if (isZodError(cause)) { return new HttpError({ statusCode: 400,