Skip to content

tRPC v12 isn’t on npm yet. The @trpc12/* packages on this site can’t be installed until it’s released. Use v11 today

tRPC

Errors

One error class, typed on the client from what resolvers return, with or without declarations.

On this page

There is one error class, TrpcError. Return error({ code }) from a resolver or a middleware, or fail with it in Effect code (Effect.fail(error(…)), yield* error(…)). The procedure's error union is inferred from those, with no declaration:

import { function error<const TCode extends string, TData = undefined>(opts: Omit<TrpcErrorOptions<TCode, TData>, "defined">): TrpcError<TCode, TData>error } from '@trpc12/trpc/server';
import { import zz } from 'zod';

const 
const byId: Procedure<{
    type: "query";
    ctx: Context;
    meta: {};
    input: {
        id: string;
    };
    output: Post;
    errors: TrpcError<"NOT_FOUND", {
        id: string;
    }> | SchemaValidationError<z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>;
    services: never;
}>
byId
= const t: TrpcRoot<Context, {}, RootDef<Context, {}>>t.TrpcRoot<Context, {}, RootDef<Context, {}>>.procedure: ProcedureBuilder<RootDef<Context, {}>>procedure
.
ProcedureBuilder<RootDef<Context, {}>>.input<z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>>(schema: z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>): ProcedureBuilder<InputDef<RootDef<Context, {}>, z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>>> (+1 overload)
input
(import zz.
function object<{
    id: z.ZodString;
}>(shape?: {
    id: z.ZodString;
} | undefined, params?: string | {
    error?: string | z.core.$ZodErrorMap<NonNullable<z.core.$ZodIssueInvalidType<unknown> | z.core.$ZodIssueUnrecognizedKeys>> | undefined;
    message?: string | undefined | undefined;
} | undefined): z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>
object
({ id: z.ZodStringid: import zz.function string(params?: string | z.core.$ZodStringParams): z.ZodString (+1 overload)string() }))
.
ProcedureBuilder<InputDef<RootDef<Context, {}>, ZodObject<{ id: ZodString; }, $strip>>>.query<Post | TrpcError<"NOT_FOUND", {
    id: string;
}>>(resolver: (opts: ResolverOpts<InputDef<RootDef<Context, {}>, z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>>>) => Post | TrpcError<"NOT_FOUND", {
    id: string;
}>): Procedure<{
    type: "query";
    ctx: Context;
    meta: {};
    input: {
        id: string;
    };
    output: Post;
    errors: TrpcError<"NOT_FOUND", {
        id: string;
    }> | SchemaValidationError<z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>;
    services: never;
}>
query
(
(
opts: ResolverOpts<InputDef<RootDef<Context, {}>, z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>>>
opts
) =>
const db: {
    post: {
        find: (id: string) => Post | undefined;
        list: () => Post[];
        create: (input: {
            title: string;
            author?: string | null;
        }) => Post;
    };
}
db
.
post: {
    find: (id: string) => Post | undefined;
    list: () => Post[];
    create: (input: {
        title: string;
        author?: string | null;
    }) => Post;
}
post
.find: (id: string) => Post | undefinedfind(
opts: ResolverOpts<InputDef<RootDef<Context, {}>, z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>>>
opts
.
ResolverOpts<InputDef<RootDef<Context, {}>, ZodObject<{ id: ZodString; }, $strip>>>.input: {
    id: string;
}
input
.id: stringid) ??
error<"NOT_FOUND", {
    id: string;
}>(opts: Omit<TrpcErrorOptions<"NOT_FOUND", {
    id: string;
}>, "defined">): TrpcError<"NOT_FOUND", {
    id: string;
}>
error
({ code: "NOT_FOUND"code: 'NOT_FOUND',
data?: {
    id: string;
} | undefined
data
: { id: stringid:
opts: ResolverOpts<InputDef<RootDef<Context, {}>, z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>>>
opts
.
ResolverOpts<InputDef<RootDef<Context, {}>, ZodObject<{ id: ZodString; }, $strip>>>.input: {
    id: string;
}
input
.id: stringid } }),
);

Declaring errors

Declaring errors with .errors() is optional. It adds typed constructors and data schemas. It also types what inference can't see: errors thrown from helpers, since a throw has no type.

import { import zz } from 'zod';

const 
const byId: Procedure<{
    type: "query";
    ctx: Context;
    meta: {};
    input: {
        id: string;
    };
    output: Post;
    errors: TrpcError<"NOT_FOUND", {
        id: string;
    }> | TrpcError<"GONE", undefined> | SchemaValidationError<z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>;
    services: never;
}>
byId
= const t: TrpcRoot<Context, {}, RootDef<Context, {}>>t.TrpcRoot<Context, {}, RootDef<Context, {}>>.procedure: ProcedureBuilder<RootDef<Context, {}>>procedure
.
ProcedureBuilder<RootDef<Context, {}>>.errors<{
    readonly NOT_FOUND: {
        readonly data: z.ZodObject<{
            id: z.ZodString;
        }, z.core.$strip>;
    };
    readonly GONE: {
        readonly status: 410;
        readonly message: "This post was removed";
    };
}>(map: {
    readonly NOT_FOUND: {
        readonly data: z.ZodObject<{
            id: z.ZodString;
        }, z.core.$strip>;
    };
    readonly GONE: {
        readonly status: 410;
        readonly message: "This post was removed";
    };
}): ProcedureBuilder<With<RootDef<Context, {}>, {
    declared: {
        NOT_FOUND: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        GONE: TrpcError<"GONE", undefined>;
    };
    errors: TrpcError<...> | TrpcError<...>;
}>>
errors
({
type NOT_FOUND: {
    readonly data: z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>;
}
NOT_FOUND
: {
data: z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>
data
: import zz.
function object<{
    id: z.ZodString;
}>(shape?: {
    id: z.ZodString;
} | undefined, params?: string | {
    error?: string | z.core.$ZodErrorMap<NonNullable<z.core.$ZodIssueInvalidType<unknown> | z.core.$ZodIssueUnrecognizedKeys>> | undefined;
    message?: string | undefined | undefined;
} | undefined): z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>
object
({ id: z.ZodStringid: import zz.function string(params?: string | z.core.$ZodStringParams): z.ZodString (+1 overload)string() }) },
type GONE: {
    readonly status: 410;
    readonly message: "This post was removed";
}
GONE
: { status: 410status: 410, message: "This post was removed"message: 'This post was removed' },
}) .
ProcedureBuilder<With<RootDef<Context, {}>, { declared: { NOT_FOUND: TrpcError<"NOT_FOUND", { id: string; }>; GONE: TrpcError<"GONE", undefined>; }; errors: TrpcError<...> | TrpcError<...>; }>>.input<z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>>(schema: z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>): ProcedureBuilder<InputDef<With<RootDef<Context, {}>, {
    declared: {
        NOT_FOUND: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        GONE: TrpcError<"GONE", undefined>;
    };
    errors: TrpcError<"NOT_FOUND", {
        id: string;
    }> | TrpcError<"GONE", undefined>;
}>, z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>>> (+1 overload)
input
(import zz.
function object<{
    id: z.ZodString;
}>(shape?: {
    id: z.ZodString;
} | undefined, params?: string | {
    error?: string | z.core.$ZodErrorMap<NonNullable<z.core.$ZodIssueInvalidType<unknown> | z.core.$ZodIssueUnrecognizedKeys>> | undefined;
    message?: string | undefined | undefined;
} | undefined): z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>
object
({ id: z.ZodStringid: import zz.function string(params?: string | z.core.$ZodStringParams): z.ZodString (+1 overload)string() }))
.
ProcedureBuilder<InputDef<With<RootDef<Context, {}>, { declared: { NOT_FOUND: TrpcError<"NOT_FOUND", { id: string; }>; GONE: TrpcError<"GONE", undefined>; }; errors: TrpcError<...> | TrpcError<...>; }>, ZodObject<...>>>.query<Post | TrpcError<"NOT_FOUND", {
    id: string;
}>>(resolver: (opts: ResolverOpts<InputDef<With<RootDef<Context, {}>, {
    declared: {
        NOT_FOUND: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        GONE: TrpcError<"GONE", undefined>;
    };
    errors: TrpcError<"NOT_FOUND", {
        id: string;
    }> | TrpcError<"GONE", undefined>;
}>, z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>>>) => Post | TrpcError<"NOT_FOUND", {
    id: string;
}>): Procedure<...>
query
(
(
opts: ResolverOpts<InputDef<With<RootDef<Context, {}>, {
    declared: {
        NOT_FOUND: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        GONE: TrpcError<"GONE", undefined>;
    };
    errors: TrpcError<"NOT_FOUND", {
        id: string;
    }> | TrpcError<"GONE", undefined>;
}>, z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>>>
opts
) =>
const db: {
    post: {
        find: (id: string) => Post | undefined;
        list: () => Post[];
        create: (input: {
            title: string;
            author?: string | null;
        }) => Post;
    };
}
db
.
post: {
    find: (id: string) => Post | undefined;
    list: () => Post[];
    create: (input: {
        title: string;
        author?: string | null;
    }) => Post;
}
post
.find: (id: string) => Post | undefinedfind(
opts: ResolverOpts<InputDef<With<RootDef<Context, {}>, {
    declared: {
        NOT_FOUND: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        GONE: TrpcError<"GONE", undefined>;
    };
    errors: TrpcError<"NOT_FOUND", {
        id: string;
    }> | TrpcError<"GONE", undefined>;
}>, z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>>>
opts
.
ResolverOpts<InputDef<With<RootDef<Context, {}>, { declared: { NOT_FOUND: TrpcError<"NOT_FOUND", { id: string; }>; GONE: TrpcError<"GONE", undefined>; }; errors: TrpcError<...> | TrpcError<...>; }>, ZodObject<...>>>.input: {
    id: string;
}
input
.id: stringid) ??
opts: ResolverOpts<InputDef<With<RootDef<Context, {}>, {
    declared: {
        NOT_FOUND: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        GONE: TrpcError<"GONE", undefined>;
    };
    errors: TrpcError<"NOT_FOUND", {
        id: string;
    }> | TrpcError<"GONE", undefined>;
}>, z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>>>
opts
.
ResolverOpts<InputDef<With<RootDef<Context, {}>, { declared: { NOT_FOUND: TrpcError<"NOT_FOUND", { id: string; }>; GONE: TrpcError<"GONE", undefined>; }; errors: TrpcError<...> | TrpcError<...>; }>, ZodObject<...>>>.errors: ErrorConstructors<{
    NOT_FOUND: TrpcError<"NOT_FOUND", {
        id: string;
    }>;
    GONE: TrpcError<"GONE", undefined>;
}>
errors
.
type NOT_FOUND: (opts: ErrorConstructorOpts<{
    id: string;
}>) => TrpcError<"NOT_FOUND", {
    id: string;
}>
NOT_FOUND
({
data: {
    id: string;
}
data
: { id: stringid:
opts: ResolverOpts<InputDef<With<RootDef<Context, {}>, {
    declared: {
        NOT_FOUND: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        GONE: TrpcError<"GONE", undefined>;
    };
    errors: TrpcError<"NOT_FOUND", {
        id: string;
    }> | TrpcError<"GONE", undefined>;
}>, z.ZodObject<{
    id: z.ZodString;
}, z.core.$strip>>>
opts
.
ResolverOpts<InputDef<With<RootDef<Context, {}>, { declared: { NOT_FOUND: TrpcError<"NOT_FOUND", { id: string; }>; GONE: TrpcError<"GONE", undefined>; }; errors: TrpcError<...> | TrpcError<...>; }>, ZodObject<...>>>.input: {
    id: string;
}
input
.id: stringid } }),
);

On the client

On the client, the errors in the union are defined: true, with their data, whether they were returned, failed or declared. Anything else arrives as a built-in error (defined: false), and it never has data:

  • An undeclared thrown error with a built-in code (throw new TrpcError({ code: 'CONFLICT', data })) keeps its code and loses its data.
  • An undeclared thrown error with a custom code, or a crash, is an INTERNAL_SERVER_ERROR. Its message is masked unless NODE_ENV is development or test, or exposeUnexpectedErrors: true.

So the client's union only has codes it can handle, and onError still sees the original error. Declare a thrown error (or return it) to give it a custom code or data on the client. There is no errorFormatter.

import { function matchError<E extends AnyTrpcError, H extends ErrorHandlers<E> & { readonly [K in keyof H]: K extends keyof ErrorHandlers<E> ? unknown : never; }>(err: E, handlers: H): HandlerResult<H>matchError, 
function safe<T, E = unknown>(promise: PromiseLike<T> & {
    readonly "~error"?: E;
}): Promise<SafeResult<T, E>>
safe
} from '@trpc12/trpc/client';
const [
const post: {
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
} | undefined
post
,
const err: (TrpcError<"NOT_FOUND", undefined> & {
    readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"FORBIDDEN", undefined> & {
    readonly defined: false;
}) | ... 20 more ... | undefined
err
] = await
safe<{
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
}, (TrpcError<"NOT_FOUND", undefined> & {
    readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
    readonly defined: false;
}) | ... 20 more ... | (TrpcError<...> & {
    ...;
})>(promise: PromiseLike<...> & {
    ...;
}): Promise<...>
safe
(
const client: TrpcClient<{
    post: {
        byId: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | SchemaValidationError<ZodObject<{
                id: ZodString;
            }, $strip>>;
            services: never;
        }>;
        list: Procedure<{
            type: "query";
            ctx: Context;
            meta: {};
            input: undefined;
            output: Post[];
            errors: never;
            services: never;
        }>;
        create: Procedure<{
            type: "mutation";
            ctx: Context;
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: TrpcError<...> | SchemaValidationError<...>;
            services: never;
        }>;
    };
}, {}, undefined, LinksTypes<...>>
client
.
post: ClientRouter<{
    byId: Procedure<{
        type: "query";
        ctx: Context;
        meta: {};
        input: {
            id: string;
        };
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }> | SchemaValidationError<ZodObject<{
            id: ZodString;
        }, $strip>>;
        services: never;
    }>;
    list: Procedure<{
        type: "query";
        ctx: Context;
        meta: {};
        input: undefined;
        output: Post[];
        errors: never;
        services: never;
    }>;
    create: Procedure<{
        type: "mutation";
        ctx: Context;
        meta: {};
        input: {
            title: string;
        };
        output: Post;
        errors: TrpcError<...> | SchemaValidationError<...>;
        services: never;
    }>;
}, {}, undefined, LinksTypes<...>>
post
.
byId: {
    query(input: {
        id: string;
    }, opts?: CallOptions<{}> | undefined): TrpcPromise<{
        id: string;
        title: string;
        author: string | null;
        createdAt: string;
    }, CallError<{
        type: "query";
        ctx: Context;
        meta: {};
        input: {
            id: string;
        };
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }> | SchemaValidationError<ZodObject<{
            id: ZodString;
        }, $strip>>;
        services: never;
    }, JsonForm, never>>;
}
byId
.
function query(input: {
    id: string;
}, opts?: CallOptions<{}> | undefined): TrpcPromise<{
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
}, CallError<{
    type: "query";
    ctx: Context;
    meta: {};
    input: {
        id: string;
    };
    output: Post;
    errors: TrpcError<"NOT_FOUND", {
        id: string;
    }> | SchemaValidationError<ZodObject<{
        id: ZodString;
    }, $strip>>;
    services: never;
}, JsonForm, never>>
query
({ id: stringid: '1' }));
if (
const err: (TrpcError<"NOT_FOUND", undefined> & {
    readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"FORBIDDEN", undefined> & {
    readonly defined: false;
}) | ... 20 more ... | undefined
err
) {
matchError<(TrpcError<"NOT_FOUND", undefined> & {
    readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"FORBIDDEN", undefined> & {
    readonly defined: false;
}) | ... 19 more ... | (TrpcError<...> & {
    ...;
}), {
    ...;
}>(err: (TrpcError<...> & {
    readonly defined: false;
}) | ... 25 more ... | (TrpcError<...> & {
    ...;
}), handlers: {
    ...;
}): void
matchError
(
const err: (TrpcError<"NOT_FOUND", undefined> & {
    readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"FORBIDDEN", undefined> & {
    readonly defined: false;
}) | ... 19 more ... | (TrpcError<...> & {
    ...;
})
err
, {
type NOT_FOUND: (e: TrpcError<"NOT_FOUND", {
    id: string;
}> & {
    readonly defined: true;
}) => void
NOT_FOUND
: (
e: TrpcError<"NOT_FOUND", {
    id: string;
}> & {
    readonly defined: true;
}
e
) => var console: Consoleconsole.Console.log(...data: any[]): voidlog(
e: TrpcError<"NOT_FOUND", {
    id: string;
}> & {
    readonly defined: true;
}
e
.data),
TrpcError<"NOT_FOUND", { id: string; }>.data: {
    id: string;
}
type BAD_REQUEST: (e: TrpcError<"BAD_REQUEST", SchemaInputErrorData<ZodObject<{
    id: ZodString;
}, $strip>>> & {
    readonly defined: true;
}) => void
BAD_REQUEST
: (
e: TrpcError<...> & {
    ...;
}
e
) => var console: Consoleconsole.Console.log(...data: any[]): voidlog(
e: TrpcError<...> & {
    ...;
}
e
.
TrpcError<"BAD_REQUEST", SchemaInputErrorData<ZodObject<{ id: ZodString; }, $strip>>>.data: SchemaInputErrorData<ZodObject<{
    id: ZodString;
}, $strip>>
data
.
SchemaInputErrorData<ZodObject<{ id: ZodString; }, $strip>>.issues: readonly ({
    readonly code: "invalid_type";
    readonly expected: $ZodInvalidTypeExpected;
    readonly path: readonly [] | readonly ["id"];
    readonly message: string;
} | {
    readonly code: "too_big";
    readonly origin: "number" | "int" | "bigint" | "date" | "string" | "array" | "set" | "file" | (string & {});
    readonly maximum: string | number;
    readonly inclusive?: boolean | undefined;
    readonly exact?: boolean | undefined;
    readonly path: readonly [] | readonly ["id"];
    readonly message: string;
} | {
    readonly code: "too_small";
    readonly origin: "number" | "int" | "bigint" | "date" | "string" | "array" | "set" | "file" | (string & {});
    ... 4 more ...;
    readonly message: string;
} | ... 8 more ... | {
    ...;
})[]
issues
),
builtin: (e: (TrpcError<"NOT_FOUND", undefined> & {
    readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"FORBIDDEN", undefined> & {
    readonly defined: false;
}) | ... 17 more ... | (TrpcError<...> & {
    readonly defined: false;
})) => void
builtin
: (
e: (TrpcError<"NOT_FOUND", undefined> & {
    readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"FORBIDDEN", undefined> & {
    readonly defined: false;
}) | ... 17 more ... | (TrpcError<...> & {
    readonly defined: false;
})
e
) => var console: Consoleconsole.Console.log(...data: any[]): voidlog(
e: (TrpcError<"NOT_FOUND", undefined> & {
    readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
    readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
    readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
    readonly defined: false;
}) | (TrpcError<"FORBIDDEN", undefined> & {
    readonly defined: false;
}) | ... 17 more ... | (TrpcError<...> & {
    readonly defined: false;
})
e
.TrpcError<TCode extends string = string, TData = unknown>.code: "NOT_FOUND" | "BAD_REQUEST" | "UNAUTHORIZED" | "PARSE_ERROR" | "UNSUPPORTED_PROTOCOL" | "PAYMENT_REQUIRED" | "FORBIDDEN" | "METHOD_NOT_SUPPORTED" | "TIMEOUT" | "CONFLICT" | "PRECONDITION_FAILED" | "PAYLOAD_TOO_LARGE" | "UNSUPPORTED_MEDIA_TYPE" | "UNPROCESSABLE_CONTENT" | "TOO_MANY_REQUESTS" | "CLIENT_CLOSED_REQUEST" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "BAD_GATEWAY" | "SERVICE_UNAVAILABLE" | "GATEWAY_TIMEOUT" | "NETWORK_ERROR" | "BAD_RESPONSE" | "CLIENT_ERROR" | "STREAM_INTERRUPTED"code),
}); }

See Errors without try/catch for safe(), matchError() and the built-in codes.

Codes and statuses

Any string is a code. The built-in ones (NOT_FOUND, UNAUTHORIZED, …) have their HTTP status; a custom code is a 400 unless its declaration (.errors() or a TrpcError.Tagged class) has a status. The status is for HTTP: errors don't carry it, and neither do error bodies or socket frames.

const t: TrpcRoot<Context, {}, RootDef<Context, {}>>t.TrpcRoot<Context, {}, RootDef<Context, {}>>.procedure: ProcedureBuilder<RootDef<Context, {}>>procedure
  .
ProcedureBuilder<RootDef<Context, {}>>.errors<{
    readonly OUT_OF_STOCK: {
        readonly status: 409;
    };
}>(map: {
    readonly OUT_OF_STOCK: {
        readonly status: 409;
    };
}): ProcedureBuilder<With<RootDef<Context, {}>, {
    declared: {
        OUT_OF_STOCK: TrpcError<"OUT_OF_STOCK", undefined>;
    };
    errors: TrpcError<"OUT_OF_STOCK", undefined>;
}>>
errors
({
type OUT_OF_STOCK: {
    readonly status: 409;
}
OUT_OF_STOCK
: { status: 409status: 409 } })
.
ProcedureBuilder<With<RootDef<Context, {}>, { declared: { OUT_OF_STOCK: TrpcError<"OUT_OF_STOCK", undefined>; }; errors: TrpcError<"OUT_OF_STOCK", undefined>; }>>.mutation<TrpcError<"OUT_OF_STOCK", undefined>>(resolver: (opts: ResolverOpts<With<RootDef<Context, {}>, {
    declared: {
        OUT_OF_STOCK: TrpcError<"OUT_OF_STOCK", undefined>;
    };
    errors: TrpcError<"OUT_OF_STOCK", undefined>;
}>>) => TrpcError<"OUT_OF_STOCK", undefined>): Procedure<{
    type: "mutation";
    ctx: Context;
    meta: {};
    input: undefined;
    output: never;
    errors: TrpcError<"OUT_OF_STOCK", undefined>;
    services: never;
}>
mutation
(() => error<"OUT_OF_STOCK", undefined>(opts: Omit<TrpcErrorOptions<"OUT_OF_STOCK", undefined>, "defined">): TrpcError<"OUT_OF_STOCK", undefined>error({ code: "OUT_OF_STOCK"code: 'OUT_OF_STOCK' })); // 409
const t: TrpcRoot<Context, {}, RootDef<Context, {}>>t.TrpcRoot<Context, {}, RootDef<Context, {}>>.procedure: ProcedureBuilder<RootDef<Context, {}>>procedure.
ProcedureBuilder<RootDef<Context, {}>>.mutation<TrpcError<"OUT_OF_STOCK", undefined>>(resolver: (opts: ResolverOpts<RootDef<Context, {}>>) => TrpcError<"OUT_OF_STOCK", undefined>): Procedure<{
    type: "mutation";
    ctx: Context;
    meta: {};
    input: undefined;
    output: never;
    errors: TrpcError<"OUT_OF_STOCK", undefined>;
    services: never;
}>
mutation
(() => error<"OUT_OF_STOCK", undefined>(opts: Omit<TrpcErrorOptions<"OUT_OF_STOCK", undefined>, "defined">): TrpcError<"OUT_OF_STOCK", undefined>error({ code: "OUT_OF_STOCK"code: 'OUT_OF_STOCK' })); // 400

In Effect code

An error's _tag is its code, so Effect code narrows with catchTag:

Effect.catchTag('NOT_FOUND', () => Effect.succeed(null));

A failure that isn't a TrpcError is a type error until it is mapped, so internals never reach clients. TrpcError.Tagged classes mark the errors clients may see (Effect).

Credits

Declared errors with .errors() follow oRPC's typed errors.