Skip to content

Validation Errors

oRPC includes built-in validation errors that work well for most cases. Customize them when you need a different message or error shape.

Customizing

You can catch validation errors with interceptors, client interceptors, or middleware applied before .input or .output.

ts
import * as 
z
from 'zod'
import {
ORPCError
,
ValidationError
} from '@orpc/server'
const
handler
= new
RPCHandler
(
router
, {
interceptors
: [
async ({
next
}) => {
try { return await
next
()
} catch (
error
) {
if (
error
instanceof
ORPCError
&&
error
.
code
=== 'BAD_REQUEST'
&&
error
.
cause
instanceof
ValidationError
) { // If you only use Zod you can safely cast to ZodIssue[] const
zodError
= new
z
.
ZodError
(
error
.
cause
.
issues
as
z
.
core
.
$ZodIssue
[])
throw new
ORPCError
('INPUT_VALIDATION_FAILED', {
message
:
z
.
prettifyError
(
zodError
),
data
:
z
.
flattenError
(
zodError
),
cause
:
error
,
}) } if (
error
instanceof
ORPCError
&&
error
.
code
=== 'INTERNAL_SERVER_ERROR'
&&
error
.
cause
instanceof
ValidationError
) { // do not expose validation details for output validation errors throw new
ORPCError
('OUTPUT_VALIDATION_FAILED', {
cause
:
error
,
}) } throw
error
} }, ], })

Typesafe Validation Errors

As explained in the error handling guide, if you throw an ORPCError whose code and data match an error defined with .errors, oRPC treats it the same as errors.[code].

This does not work in interceptors. Use client interceptors or middleware applied before .input or .output instead.

ts
import { 
ORPCError
,
os
,
ValidationError
} from '@orpc/server'
import * as
z
from 'zod'
const
base
=
os
.
errors
({
INPUT_VALIDATION_FAILED
: {
data
:
z
.
object
({
formErrors
:
z
.
array
(
z
.
string
()),
fieldErrors
:
z
.
record
(
z
.
string
(),
z
.
array
(
z
.
string
()).
optional
()),
}), }, }) const
example
=
base
.
input
(
z
.
object
({
id
:
z
.
uuid
() }))
.
handler
(() => { /** do something */ })
const
handler
= new
RPCHandler
({
example
}, {
clientInterceptors
: [
async ({
next
}) => {
try { return await
next
()
} catch (
error
) {
if (
error
instanceof
ORPCError
&&
error
.
code
=== 'BAD_REQUEST'
&&
error
.
cause
instanceof
ValidationError
) { // If you only use Zod you can safely cast to ZodIssue[] const
zodError
= new
z
.
ZodError
(
error
.
cause
.
issues
as
z
.
core
.
$ZodIssue
[])
throw new
ORPCError
('INPUT_VALIDATION_FAILED', {
message
:
z
.
prettifyError
(
zodError
),
data
:
z
.
flattenError
(
zodError
),
cause
:
error
,
}) } throw
error
} }, ], })

Released under the MIT License.