tRPCSeniorExperience

Как понять, что проблема в проекте связана с tRPC, а не с API, сетью, дизайном состояния или плохой архитектурой?

Диагностику начинают с изоляции: если прямой fetch к /api/trpc воспроизводит проблему — виноват сервер или сеть; если только в UI — проблема в клиенте, кэше или компоненте. tRPC редко является первопричиной.

Принцип диагностики: изоляция слоёв

tRPC — тонкая транспортная обёртка. Большинство проблем, которые кажутся «проблемами tRPC», на самом деле в одном из пяти слоёв: сеть, сервер (бизнес-логика), кэш (React Query), компонент (state/rendering), архитектура данных. Задача — последовательно исключать слои.

Шаг 1: Воспроизвести без клиента tRPC

Сделайте прямой HTTP-запрос к процедуре через curl или fetch в браузере:

// В консоли браузера или Node.js REPL
const res = await fetch('/api/trpc/user.getById?batch=1&input={"0":{"json":{"id":1}}}');
console.log(await res.json());

Если ответ некорректен — проблема на сервере или в сети, не в tRPC-клиенте.

Шаг 2: Изолировать React Query от tRPC

Проверьте состояние кэша через React Query DevTools:

  • Какой queryKey используется? Нет ли дублей из-за разных input-объектов?
  • Статус: stale, fresh, error? Когда последний раз был fetchedAt?
  • Если данные есть в кэше, но компонент не отображает — проблема в компоненте, не в tRPC.

Шаг 3: Проверить серверную логику напрямую

В Next.js вызовите процедуру через createCaller в юнит-тесте или серверном компоненте, минуя HTTP:

import { createCaller } from '@/server/router';

// В test-файле или Server Action
const caller = createCaller({ session: mockSession, db: testDb });
const result = await caller.user.getById({ id: 1 });
console.log(result); // Если ошибка здесь — баг в бизнес-логике

Шаг 4: Идентифицировать специфичные баги tRPC

После исключения сети, сервера и React Query остаётся малый класс реальных проблем tRPC:

  • Сериализация: tRPC использует superjson по умолчанию; Date, Map, Set могут некорректно сериализоваться, если трансформер не настроен.
  • Ошибки типов в runtime: несовпадение версий AppRouter между клиентом и сервером при раздельном деплое.
  • Middleware context: если createContext не передаёт нужные данные (session, db) — ошибка выглядит как tRPC, но это контекст.

Шаг 5: Отличить архитектурную проблему

Если несколько компонентов запрашивают одни данные и вы видите N+1 запросов — это не баг tRPC, а архитектурная проблема. Решение: useSuspenseQuery с prefetch или вынос данных в общий провайдер.

Подводные камни

  • TRPCClientError vs TRPCError: клиентская ошибка приходит обёрнутой; error.data?.code и error.data?.zodError — правильные поля для диагностики валидации.
  • Batch-запросы маскируют ошибки: если одна из 5 процедур в batch падает, остальные могут вернуть успех; нужно проверять каждый элемент ответа.
  • superjson нужно регистрировать на обоих концах: transformer в createTRPCReact и в адаптере сервера должны совпадать, иначе даты десериализуются как строки.
  • Context не типизирован до createContext: ошибка ctx.session is undefined — это middleware, а не tRPC.
  • React Query DevTools отключены в production: добавьте временное логирование через queryClient.getQueryCache().getAll() для prod-диагностики.

What hurts your answer

  • Сразу обвинять tRPC, не проверив соседние слои системы
  • Чинить симптом без минимального воспроизведения и evidence
  • Не учитывать версии, конфигурацию, окружение и recent changes

What they're listening for

  • Умеет локализовать проблему вокруг tRPC
  • Двигается от симптома к гипотезам и проверкам
  • Отличает баг инструмента от ошибки использования или окружения

Related topics