LEARN · DEBUGGING GUIDE

Diagnosing tRPC Procedure Errors in Next.js Apps

tRPC errors in Next.js are rarely self-explanatory. Cut through cryptic stack traces and pinpoint the real cause of broken procedures with a systematic approach.

IntermediateNext.js4 min read

What this usually means

tRPC procedure errors in Next.js typically indicate mismatches between client and server routers, incorrect procedure names, or serialization/validation problems (e.g., Zod or JSON issues). Sometimes, it's a deployment artifact or a stale build, especially when Next.js API routes or file structure don't match the expected router definitions. These errors rarely expose internals client-side, so the real issue may be hidden unless you directly inspect the API route logs and the router structure.

( 01 )Fast diagnosis

The first ten minutes — establish facts before touching code.

  • 1Run `curl -v http://localhost:3000/api/trpc/<procedure>?input={}` to trigger failure directly, observe raw error details.
  • 2Check `pages/api/trpc/[trpc].ts` (or `app/api/trpc/[trpc]/route.ts` in app dir) for correct import of your rootRouter.
  • 3Log all available procedure paths by injecting `console.log(Object.keys(appRouter._def.procedures))` in the API handler.
  • 4Look for mismatches between client-side tRPC procedure calls (e.g., `trpc.foo.bar.useQuery()`) and server router definition.
  • 5Temporarily set `NODE_ENV=development` and `TRPC_LOG_LEVEL=debug` to get full error traces in your terminal.
( 02 )Where to look

The specific files, logs, configs, and dashboards that usually own this bug.

  • searchpages/api/trpc/[trpc].ts or app/api/trpc/[trpc]/route.ts files
  • searchtrpc.ts router definition — especially the rootRouter export
  • searchTypeScript build output (`.next` folder) for stale builds
  • searchBrowser network tab: look at /api/trpc/<procedure> responses
  • searchServer console output — look for any stack traces or warnings
  • searchpackage.json dependencies (`trpc`, `zod`, and Next versions must be compatible)
( 03 )Common root causes

Practical causes, not theory. These are the things you will actually find.

  • warningProcedure path typo: client calls `trpc.posts.getAll` but server has `post.getAll`
  • warningRouter not properly exported or imported in /api handler
  • warningZod schema validation fails silently (e.g., missing required field in input)
  • warningAPI handler wraps the router with the wrong context or provider
  • warningNext.js build cache stale after router structure change
  • warningTypeScript type drift between client and server (misaligned outputs/inputs)
( 04 )Fix patterns

Concrete fix directions. Pick the one that matches your root cause.

  • buildAlign procedure paths exactly — diff client call chain vs. router keys
  • buildRestart dev server after router changes (`pnpm dev` or `yarn dev`)
  • buildAdd `console.log` to router and context creation to verify handler codepaths
  • buildExplicitly catch and rethrow errors with details in procedures for visibility
  • buildVerify Zod validators match expected input shapes on both client and server
  • buildDelete `.next`, `.turbo`, and run a fresh build to clear stale artifacts
( 05 )How to verify

A fix you cannot prove is a guess. Close the loop.

  • verifiedHit the endpoint with valid/invalid data via curl and confirm expected error codes
  • verifiedCheck that tRPC devtools show correct response shape and no INTERNAL_SERVER_ERRORs
  • verifiedTrigger client mutation/query and see real results (not just error fallback)
  • verifiedAdd temporary `console.log('called')` in procedure and see server-side output
  • verifiedRun `npm run build && npm start` to check for prod/runtime discrepancies
( 06 )Mistakes to avoid

Things that make this bug worse or harder to find.

  • warningRelying only on browser error messages — always check server logs
  • warningAssuming HMR reloads fix router export changes; manual restart needed
  • warningIgnoring TypeScript errors or 'type widening' warnings across tRPC client/server
  • warningTesting only in dev; some issues manifest only in production build
  • warningLeaving Zod schemas permissive/empty for 'quick fixes' — this hides real problems
  • warningNeglecting to sync client and server dependency versions
( 07 )War story

Missing Procedure Export Broke Production tRPC Calls

Full Stack EngineerNext.js 13 (app dir), tRPC v10, PostgreSQL, TypeScript 4.9

Timeline

  1. 09:10Merged new 'admin.getStats' query to appRouter on feature branch.
  2. 09:12Serverless deployment completed, no errors in CI.
  3. 09:14QA team reports 500 errors on dashboard page — admin stats not loading.
  4. 09:17Checked browser: tRPC devtools shows 'INTERNAL_SERVER_ERROR', no details.
  5. 09:19SSH’d into prod pod, tailed logs: 'No procedure found for path "admin.getStats"'.
  6. 09:25Discovered rootRouter was imported from a stale file, missing the new procedure.
  7. 09:30Patched [trpc]/route.ts to import the current router version, redeployed.
  8. 09:32Live tests confirmed stats loaded, errors cleared from logs and frontend.

When I added a new 'admin.getStats' endpoint to our tRPC router, everything compiled locally, and CI passed. But immediately after deploying, the dashboard page broke with a generic 500 error and no useful stack trace.

At first, I suspected a data or auth bug, but the tRPC devtools just showed a generic INTERNAL_SERVER_ERROR. On digging into the serverless logs, the API handler was clearly logging 'No procedure found', which pointed to a routing or export mismatch.

After some digging, I found that the API route was importing a version of the rootRouter that hadn't been updated — a classic copy-paste import left over from an earlier refactor. Repointing the import to the real router fixed it, and the endpoint worked instantly.

Root cause

API route imported a stale router missing the new procedure registration.

The fix

Updated the import in [trpc]/route.ts to reference the current rootRouter definition.

The lesson

Any time a new procedure silently fails, check router imports for staleness before assuming validation or data bugs.

( 08 )Tracing Procedure Paths Across Client and Server

tRPC's procedure lookup is string-based and case-sensitive. For example, if your client calls `trpc.profile.getInfo.useQuery()`, the server router must define `profile.getInfo`. Even a minor mismatch (e.g., `profiles.getInfo`) will yield the dreaded 'No procedure found' error.

Automate a router key dump: in your API handler, temporarily insert `console.log(Object.keys(appRouter._def.procedures))`. This immediately surfaces typos or missing linkages.

( 09 )Why Error Messages Are So Vague

tRPC intentionally gives as little information as possible to the client for security reasons. All unhandled errors become INTERNAL_SERVER_ERROR with no stack.

Always look server-side for root causes. If your logs are silent, set `TRPC_LOG_LEVEL=debug` or inject explicit `console.error` statements in both context and procedure logic.

( 10 )The Real Cost of Stale Builds in Next.js

Next.js caches aggressively, and router changes don't always trigger HMR reload or clean rebuilds. Especially when using the app directory structure or serverless platforms, a router change might not propagate without a manual restart.

Force a clean build with `rm -rf .next` before running locally, and ensure your deployment triggers a full step, not an incremental one, when router files change.

( 11 )Type Safety and Why It Isn't Enough

TypeScript provides great autocomplete, but if you accidentally import the wrong router or mutate types between client and server, you'll get run-time resolution failures. For instance, changing a Zod schema but forgetting to update the caller will pass type checks but fail at runtime.

Always couple router and client upgrades, and lock package versions to ensure compatibility. Don't let types drift, even across minor tRPC or Zod upgrades.

Frequently asked questions

Why does tRPC return INTERNAL_SERVER_ERROR with no stacktrace?

tRPC masks all errors by default for security. To see details, check server logs, set `TRPC_LOG_LEVEL=debug`, and add explicit logging in your API handler.

How can I confirm if my client and server procedure paths match?

Log `Object.keys(appRouter._def.procedures)` in your API handler. Compare each key to your client-side procedure calls for typos or case mismatches.

What causes Zod input validation errors in tRPC procedures?

When the client sends inputs not matching the Zod schema, the server will reject the call—often with an 'Input validation failed' error. Double-check your schemas and client payloads.

Will Next.js hot reload always pick up router changes?

No. Especially with app directory or non-standard builds, you may need to manually restart the dev server after changing router definitions or imports.

How do stale router imports happen in Next.js?

Common after refactors or copy-pasting, when router files are moved but API routes still import old definitions. Always verify imports against your latest router location.