calcom/cal.diy · error · TRPCError

${error.message as TRPCErrorCode}

Error message

${error.message as TRPCErrorCode}

What it means

Re-thrown as a TRPCError whose code is the upstream error.message, but only when that message is a key present in TRPC_ERROR_MAP (i.e. a known tRPC error code). The slots controller bridges an underlying tRPC-layer error into the Nest response pipeline by mapping its textual code back into a structured TRPCError. If the message is not in the map, control falls through to the final `throw error`.

Source

Thrown at apps/api/v2/src/modules/slots/slots-2024-04-15/controllers/slots.controller.ts:223

        query.timeZone
      );

      return {
        data: {
          slots,
        },
        status: SUCCESS_STATUS,
      };
    } catch (error) {
      if (error instanceof Error) {
        if (error.message.includes("Invalid time range given")) {
          throw new BadRequestException(
            "Invalid time range given - check the 'startTime' and 'endTime' query parameters."
          );
        }

        if (TRPC_ERROR_MAP[error.message as keyof typeof TRPC_ERROR_CODE]) {
          throw new TRPCError({ code: error.message as TRPCErrorCode });
        }
      }

      throw error;
    }
  }
}

View on GitHub (pinned to 176037d0af)

Solutions

  1. Handle the upstream cause: a BAD_REQUEST means bad inputs, UNAUTHORIZED means auth — fix the triggering condition rather than the wrapper.
  2. If a legitimate new tRPC code is not in TRPC_ERROR_MAP, add it to the map so it translates instead of falling through to a raw 500.
  3. Catch TRPCError in your client and switch on error.code to drive UX.

Example fix

// before — new code thrown but not mapped, surfaces as raw error
// (TRPC_ERROR_MAP missing 'PAYLOAD_TOO_LARGE')
// after — extend the map
TRPC_ERROR_MAP = { ...TRPC_ERROR_MAP, PAYLOAD_TOO_LARGE: 'PAYLOAD_TOO_LARGE' } as const;
// client:
try { await api.getSlots(q); }
catch (e) { if (e.code === 'UNAUTHORIZED') redirectToLogin(); }
Defensive patterns

Strategy: try-catch

Type guard

const isTrpcCode = (code: unknown): boolean =>
  typeof code === 'string' &&
  ['BAD_REQUEST','UNAUTHORIZED','FORBIDDEN','NOT_FOUND','TIMEOUT','CONFLICT','INTERNAL_SERVER_ERROR'].includes(code);

Try / catch

try { await api.getSlots(q); }
catch (e) {
  if (isTrpcCode(e.code)) {
    switch (e.code) {
      case 'UNAUTHORIZED': redirectToLogin(); break;
      case 'NOT_FOUND': showNotFound(); break;
      default: throw e;
    }
  } else throw e;
}

Prevention

When it happens

Trigger: getAvailableSlots throws a tRPC-style error message such as 'BAD_REQUEST', 'UNAUTHORIZED', 'FORBIDDEN', 'NOT_FOUND', 'INTERNAL_SERVER_ERROR', etc. — any key of TRPC_ERROR_CODE — which the controller then lifts into a TRPCError for the global trpc-exception filter to render.

Common situations: Reusing core booking/slot tRPC procedures from the API v2 controller; the shared procedure throws a typed tRPC error and the Nest wrapper must translate it; version drift where a new tRPC code is thrown but TRPC_ERROR_MAP has not been updated.

Related errors


AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12). Data as JSON: /api/errors/5cf80b7157dfc007. Report an issue: GitHub.