Error Handling
On this page
A failed procedure call rejects with a TRPCClientError. You can either let it throw and catch it, or use safe() to get it back as a type-safe value.
Catching a thrown error
query() and mutate() behave like any other promise, so a try/catch works as you would expect. TypeScript has no way to describe what a function throws, though, so cause arrives as unknown and has to be narrowed:
client.ts
import { TRPCClientError } from '@trpc/client';
import type { AppRouter } from './server';
import { trpc } from './trpc';
try {
const post = await trpc.post.byId.query('1');
} catch (cause) {
if (cause instanceof TRPCClientError) {
console.log(cause.data);
} else {
// something that isn't a tRPC error
}
}See Inferring Types for a reusable isTRPCClientError guard.
Errors as values with safe()
safe() awaits a query() or mutate() call without letting it throw, handing back a [data, error] pair instead. Exactly one side is ever set, so checking either one narrows the other:
client.ts
import { safe } from '@trpc/client';
import { trpc } from './trpc';
const [post, error] = await safe(trpc.post.byId.query('1'));
if (error) {
console.log(error.data);
} else {
console.log(post.title);
}