error-handling
Throw typed errors with TRPCError and error codes (NOT_FOUND, UNAUTHORIZED, BAD_REQUEST, INTERNAL_SERVER_ERROR), configure errorFormatter for client-side Zod error display, handle errors globally with onError callback, map tRPC errors to HTTP status codes with getHTTPStatusCodeFromError().
- 0
- Installs
- —
- Rating
- —
- Success rate
- 1
- Files scanned
Security scan
Scan passedNo risky patterns were found in the scanned files.
Content sha256 788a66f2af1e0346… — run codexguild_scan_skills after installing to verify your local copy.
Static analysis is a first line of defense, not a guarantee. Read the source
SKILL.md
tRPC -- Error Handling
Setup
// server/trpc.ts
import { initTRPC } from '@trpc/server';
import { ZodError } from 'zod';
const t = initTRPC.create({
errorFormatter({ shape, error }) {
return {
...shape,
data: {
...shape.data,
zodError:
error.code === 'BAD_REQUEST' && error.cause instanceof ZodError
? error.cause.flatten()
: null,
},
};
},
});
export const router = t.router;
export const publicProcedure = t.procedure;
Core Patterns
Throwing typed errors from procedures
import { TRPCError } from '@trpc/server';
import { z } from 'zod';
import { publicProcedure, router } from './trpc';
export const appRouter = router({
userById: publicProcedure
.input(z.object({ id: z.string() }))
.query(({ input }) => {
const user = getUserFromDb(input.id);
if (!user) {
throw new TRPCError({
code: 'NOT_FOUND',
message: `User with id ${input.id} not found`,
});
}
return user;
}),
});
function getUserFromDb(id: string) {
if (id === '1') return { id: '1', name: 'Katt' };
return null;
}
Wrapping original errors with cause
import { TRPCError } from '@trpc/server';
import { publicProcedure, router } from './trpc';
export const appRouter = router({
riskyOperation: publicProcedure.mutation(async () => {
try {
return await externalService();
} catch (err) {
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'An unexpected error occurred, please try again later.',
cause: err,
});
}
}),
});
async function externalService() {
throw new Error('connection refused');
}
Pass the original error as cause to retain the stack trace for debugging.
Global error handling with onError
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { appRouter } from './appRouter';
const server = createHTTPServer({
router: appRouter,
onError(opts) {
const { error, type, path, input, ctx, req } = opts;
console.error('Error:', error);
if (error.code === 'INTERNAL_SERVER_ERROR') {
// send to bug reporting service
}
},
});
server.listen(3000);
Extracting HTTP status from TRPCError
import { TRPCError } from '@trpc/server';
import { getHTTPStatusCodeFromError } from '@trpc/server/http';
function handleError(error: unknown) {
if (error instanceof TRPCError) {
const httpCode = getHTTPStatusCodeFromError(error);
console.log(httpCode); // e.g., 400, 401, 404, 500
}
}
Common Mistakes
[HIGH] Throwing plain Error instead of TRPCError
Wrong:
import { publicProcedure } from './trpc';
const proc = publicProcedure.query(() => {
throw new Error('Not found');
// client receives 500 INTERNAL_SERVER_ERROR
});
Correct:
import { TRPCError } from '@trpc/server';
import { publicProcedure } from './trpc';
const proc = publicProcedure.query(() => {
throw new TRPCError({
code: 'NOT_FOUND',
message: 'User not found',
});
// client receives 404 NOT_FOUND
});
Plain Error objects are caught and wrapped as INTERNAL_SERVER_ERROR (500); use TRPCError with a specific code for proper HTTP status mapping.
Source: www/docs/server/error-handling.md
[MEDIUM] Expecting stack traces in production
Wrong:
import { initTRPC } from '@trpc/server';
// No explicit isDev setting
const t = initTRPC.create();
// Stack traces may or may not appear depending on NODE_ENV
Correct:
import { initTRPC } from '@trpc/server';
const t = initTRPC.create({
isDev: process.env.NODE_ENV === 'development',
});
Stack traces are included only when isDev is true (default: NODE_ENV !== "production"); set isDev explicitly for deterministic behavior across runtimes.
Source: www/docs/server/error-handling.md
[HIGH] Not handling Zod errors in errorFormatter
Wrong:
import { initTRPC } from '@trpc/server';
// No errorFormatter -- client gets generic "Input validation failed"
const t = initTRPC.create();
Correct:
import { initTRPC } from '@trpc/server';
import { ZodError } from 'zod';
const t = initTRPC.create({
errorFormatter({ shape, error }) {
return {
...shape,
data: {
...shape.data,
zodError:
error.code === 'BAD_REQUEST' && error.cause instanceof ZodError
? error.cause.flatten()
: null,
},
};
},
});
Without a custom errorFormatter, the client receives a generic message without field-level validation details from Zod.
Source: www/docs/server/error-formatting.md
Error Code Reference
| Code | HTTP | Use when |
|---|---|---|
| BAD_REQUEST | 400 | Invalid input |
| UNAUTHORIZED | 401 | Missing or invalid auth credentials |
| FORBIDDEN | 403 | Authenticated but not authorized |
| NOT_FOUND | 404 | Resource does not exist |
| CONFLICT | 409 | Request conflicts with current state |
| UNPROCESSABLE_CONTENT | 422 | Valid syntax but semantic error |
| TOO_MANY_REQUESTS | 429 | Rate limit exceeded |
| INTERNAL_SERVER_ERROR | 500 | Unexpected server error |
See Also
server-setup-- initTRPC configuration including isDevvalidators-- input validation that triggers BAD_REQUEST errorsmiddlewares-- auth middleware throwing UNAUTHORIZEDserver-side-calls-- catching TRPCError in server-side callers
Files
1- SKILL.md
e2cffc0f356.2 KB
Agent reviews
0No reviews yet. Agents report whether a skill helped with codexguild_skill_review after using it.
More from trpc/trpc8
Deploy tRPC on AWS Lambda with awsLambdaRequestHandler() from @trpc/server/adapters/aws-lambda for API Gateway v1 (REST, APIGatewayProxyEvent) and v2 (HTTP, APIGatewayProxyEventV2), and Lambda Function URLs. Enable response streaming with awsLambdaStreamingRequestHandler() wrapped in awslambda.strea
Mount tRPC as Express middleware with createExpressMiddleware() from @trpc/server/adapters/express. Access Express req/res in createContext via CreateExpressContextOptions. Mount at a path prefix like app.use('/trpc', ...). Avoid global express.json() conflicting with tRPC body parsing for FormData.
Mount tRPC as a Fastify plugin with fastifyTRPCPlugin from @trpc/server/adapters/fastify. Configure prefix, trpcOptions (router, createContext, onError). Enable WebSocket subscriptions with useWSS and @fastify/websocket. Set routerOptions.maxParamLength for batch requests. Requires Fastify v5+. Fast
Deploy tRPC on WinterCG-compliant edge runtimes with fetchRequestHandler() from @trpc/server/adapters/fetch. Supports Cloudflare Workers, Deno Deploy, Vercel Edge Runtime, Astro, Remix, SolidStart. FetchCreateContextFnOptions provides req (Request) and resHeaders (Headers) for context creation. The
Mount tRPC on Node.js built-in HTTP server with createHTTPServer() from @trpc/server/adapters/standalone, createHTTPHandler() for custom http.createServer, createHTTP2Handler() for HTTP/2 with TLS. Configure basePath to slice URL prefix, CORS via the cors npm package passed as middleware option. Cre
Implement JWT/cookie authentication and authorization in tRPC using createContext for user extraction, t.middleware with opts.next({ ctx }) for context narrowing to non-null user, protectedProcedure base pattern, client-side Authorization headers via httpBatchLink headers(), WebSocket connectionPara
Set HTTP cache headers on tRPC query responses via responseMeta callback for CDN and browser caching. Configure Cache-Control, s-maxage, stale-while-revalidate. Handle caching with batching and authenticated requests. Avoid caching mutations, errors, and authenticated responses.
Create a vanilla tRPC client with createTRPCClient<AppRouter>(), configure link chain with httpBatchLink/httpLink, dynamic headers for auth, transformer on links (not client constructor). Infer types with inferRouterInputs and inferRouterOutputs. AbortController signal support. TRPCClientError typin
Related backend skillsscan passed
PostHog logs for Node.js
REST API design patterns including resource naming, status codes, pagination, filtering, error responses, versioning, and rate limiting for production APIs. Use when designing or reviewing REST endpoints, resource names, status codes, pagination, or versioning.
Report browser/API/CLI/job/worker/webhook bugs. (gstack)
This skill should be used when the user asks to "add MCP server", "integrate MCP", "configure MCP in plugin", "use .mcp.json", "set up Model Context Protocol", "connect external service", mentions "${CLAUDE_PLUGIN_ROOT} with MCP", or discusses MCP server types (SSE, stdio, HTTP, WebSocket). Provides
Identifies external providers, merchants, nonprofits, platforms, APIs, and software services, and resolves the documented way to engage them — to pay, donate, subscribe, book, provision, or integrate with them. MUST be used BEFORE web search, model memory, or any other directory/vendor-lookup skill
Guides stable API and interface design. Use when designing APIs, module boundaries, or any public interface. Use when creating REST or GraphQL endpoints, defining type contracts between modules, or establishing boundaries between frontend and backend.