0
# Error Handling
1
2
Structured error types with granular issue reporting and formatting utilities.
3
4
## ZodError Class
5
6
```typescript { .api }
7
/**
8
* Main error class for Zod validation failures
9
*/
10
class ZodError<T = any> extends Error {
11
/** Array of validation issues */
12
issues: ZodIssue[];
13
14
/** Alias for issues (deprecated) */
15
errors: ZodIssue[];
16
17
/** Error name (always "ZodError") */
18
name: "ZodError";
19
20
/** Formatted error message */
21
message: string;
22
23
constructor(issues: ZodIssue[]);
24
25
/**
26
* Format error as tree structure matching data shape
27
* @param mapper - Optional function to transform issues
28
* @returns Formatted error tree with _errors arrays at each level
29
*/
30
format<U = string>(mapper?: (issue: ZodIssue) => U): ZodFormattedError<T, U>;
31
32
/**
33
* Flatten error structure into form and field errors
34
* @param mapper - Optional function to transform issues
35
* @returns Flattened error object with formErrors and fieldErrors
36
*/
37
flatten<U = string>(mapper?: (issue: ZodIssue) => U): ZodFlattenedError<U>;
38
39
/**
40
* String representation of error
41
* @returns Error string with all issues listed
42
*/
43
toString(): string;
44
45
/**
46
* Add issue to error (deprecated)
47
* @param issue - Issue to add
48
*/
49
addIssue(issue: ZodIssue): void;
50
51
/**
52
* Add multiple issues (deprecated)
53
* @param issues - Issues to add
54
*/
55
addIssues(issues: ZodIssue[]): void;
56
57
/** Check if error has no issues */
58
get isEmpty(): boolean;
59
60
/** Get error as JSON (alias for issues) */
61
get errors(): ZodIssue[];
62
}
63
64
interface ZodFormattedError<T = any, U = string> {
65
_errors: U[];
66
[key: string]: ZodFormattedError<any, U> | U[];
67
}
68
69
interface ZodFlattenedError<U = string> {
70
formErrors: U[];
71
fieldErrors: { [k: string]: U[] };
72
}
73
```
74
75
**Examples:**
76
```typescript
77
try {
78
UserSchema.parse(invalidData);
79
} catch (error) {
80
if (error instanceof z.ZodError) {
81
// Access issues
82
console.log(error.issues);
83
84
// Format as tree
85
const formatted = error.format();
86
// { _errors: [], name: { _errors: ["Too short"] }, ... }
87
88
// Flatten errors
89
const flattened = error.flatten();
90
// { formErrors: [], fieldErrors: { name: ["Too short"], ... } }
91
92
// String representation
93
console.log(error.toString());
94
console.log(error.message);
95
96
// Check if empty
97
console.log(error.isEmpty); // false
98
}
99
}
100
```
101
102
## ZodIssue Types
103
104
```typescript { .api }
105
interface ZodIssue {
106
code: ZodIssueCode;
107
path: (string | number)[];
108
message: string;
109
}
110
111
enum ZodIssueCode {
112
invalid_type = "invalid_type",
113
invalid_literal = "invalid_literal",
114
custom = "custom",
115
invalid_union = "invalid_union",
116
invalid_union_discriminator = "invalid_union_discriminator",
117
invalid_enum_value = "invalid_enum_value",
118
unrecognized_keys = "unrecognized_keys",
119
invalid_arguments = "invalid_arguments",
120
invalid_return_type = "invalid_return_type",
121
invalid_date = "invalid_date",
122
invalid_string = "invalid_string",
123
too_small = "too_small",
124
too_big = "too_big",
125
invalid_intersection_types = "invalid_intersection_types",
126
not_multiple_of = "not_multiple_of",
127
not_finite = "not_finite",
128
}
129
130
// Specific issue types
131
interface ZodInvalidTypeIssue extends ZodIssue {
132
code: "invalid_type";
133
expected: ZodParsedType;
134
received: ZodParsedType;
135
}
136
137
interface ZodTooSmallIssue extends ZodIssue {
138
code: "too_small";
139
type: "string" | "number" | "bigint" | "array" | "set" | "date";
140
minimum: number | bigint;
141
inclusive: boolean;
142
exact?: boolean;
143
}
144
145
interface ZodTooBigIssue extends ZodIssue {
146
code: "too_big";
147
type: "string" | "number" | "bigint" | "array" | "set" | "date";
148
maximum: number | bigint;
149
inclusive: boolean;
150
exact?: boolean;
151
}
152
153
interface ZodCustomIssue extends ZodIssue {
154
code: "custom";
155
params?: { [k: string]: any };
156
}
157
158
interface ZodInvalidStringIssue extends ZodIssue {
159
code: "invalid_string";
160
validation: "email" | "url" | "uuid" | "regex" | "datetime" | "ip"
161
| { includes: string; position?: number }
162
| { startsWith: string }
163
| { endsWith: string };
164
}
165
166
interface ZodInvalidUnionIssue extends ZodIssue {
167
code: "invalid_union";
168
unionErrors: ZodError[];
169
}
170
171
interface ZodInvalidEnumValueIssue extends ZodIssue {
172
code: "invalid_enum_value";
173
options: any[];
174
received: any;
175
}
176
177
interface ZodUnrecognizedKeysIssue extends ZodIssue {
178
code: "unrecognized_keys";
179
keys: string[];
180
}
181
182
interface ZodInvalidLiteralIssue extends ZodIssue {
183
code: "invalid_literal";
184
expected: any;
185
received: any;
186
}
187
188
interface ZodInvalidUnionDiscriminatorIssue extends ZodIssue {
189
code: "invalid_union_discriminator";
190
options: any[];
191
}
192
193
interface ZodInvalidArgumentsIssue extends ZodIssue {
194
code: "invalid_arguments";
195
argumentsError: ZodError;
196
}
197
198
interface ZodInvalidReturnTypeIssue extends ZodIssue {
199
code: "invalid_return_type";
200
returnTypeError: ZodError;
201
}
202
203
interface ZodInvalidDateIssue extends ZodIssue {
204
code: "invalid_date";
205
}
206
207
interface ZodInvalidIntersectionTypesIssue extends ZodIssue {
208
code: "invalid_intersection_types";
209
}
210
211
interface ZodNotMultipleOfIssue extends ZodIssue {
212
code: "not_multiple_of";
213
multipleOf: number | bigint;
214
}
215
216
interface ZodNotFiniteIssue extends ZodIssue {
217
code: "not_finite";
218
}
219
220
type ZodParsedType =
221
| "string" | "number" | "bigint" | "boolean" | "date" | "symbol"
222
| "undefined" | "null" | "array" | "object" | "map" | "set"
223
| "function" | "promise" | "nan" | "unknown";
224
```
225
226
## Error Formatting
227
228
```typescript { .api }
229
/**
230
* Format error as tree structure matching data shape
231
* @param error - ZodError to format
232
* @param mapper - Optional function to transform issues
233
* @returns Formatted error tree with _errors arrays at each level
234
*/
235
function formatError<T = any, U = string>(
236
error: ZodError<T>,
237
mapper?: (issue: ZodIssue) => U
238
): ZodFormattedError<T, U>;
239
240
/**
241
* Flatten error structure into form and field errors
242
* @param error - ZodError to flatten
243
* @param mapper - Optional function to transform issues
244
* @returns Flattened error object with formErrors and fieldErrors
245
*/
246
function flattenError<U = string>(
247
error: ZodError,
248
mapper?: (issue: ZodIssue) => U
249
): ZodFlattenedError<U>;
250
251
/**
252
* Format error as tree (alias for formatError)
253
* @param error - ZodError to format
254
* @param mapper - Optional function to transform issues
255
* @returns Formatted error tree
256
*/
257
function treeifyError<T = any, U = string>(
258
error: ZodError<T>,
259
mapper?: (issue: ZodIssue) => U
260
): ZodFormattedError<T, U>;
261
262
/**
263
* Pretty-print error as readable string
264
* @param error - ZodError to prettify
265
* @returns Formatted error string with path: message format
266
*/
267
function prettifyError(error: ZodError): string;
268
```
269
270
**Examples:**
271
```typescript
272
const result = ComplexSchema.safeParse(data);
273
274
if (!result.success) {
275
const error = result.error;
276
277
// Format as tree
278
const formatted = error.format();
279
// {
280
// _errors: [],
281
// name: { _errors: ["Too short"] },
282
// age: { _errors: ["Must be positive"] },
283
// address: {
284
// _errors: [],
285
// street: { _errors: ["Required"] }
286
// }
287
// }
288
289
// Flatten errors
290
const flattened = error.flatten();
291
// {
292
// formErrors: [],
293
// fieldErrors: {
294
// name: ["Too short"],
295
// age: ["Must be positive"],
296
// "address.street": ["Required"]
297
// }
298
// }
299
300
// Custom mapper
301
const customFormatted = error.format((issue) => ({
302
code: issue.code,
303
message: issue.message,
304
}));
305
306
// Prettify
307
const pretty = z.prettifyError(error);
308
// name: Too short
309
// age: Must be positive
310
// address.street: Required
311
}
312
```
313
314
## Error Handling Patterns
315
316
```typescript
317
// Pattern 1: Try-catch with parse
318
try {
319
const data = schema.parse(input);
320
// Use data
321
} catch (error) {
322
if (error instanceof z.ZodError) {
323
console.error(error.issues);
324
}
325
}
326
327
// Pattern 2: Safe parse (preferred)
328
const result = schema.safeParse(input);
329
if (!result.success) {
330
console.error(result.error.issues);
331
} else {
332
// Use result.data
333
}
334
335
// Pattern 3: Express middleware
336
function validateBody(schema: z.ZodSchema) {
337
return (req, res, next) => {
338
const result = schema.safeParse(req.body);
339
if (!result.success) {
340
return res.status(400).json({
341
errors: result.error.flatten().fieldErrors,
342
});
343
}
344
req.validatedBody = result.data;
345
next();
346
};
347
}
348
349
// Pattern 4: Issue inspection
350
const result = schema.safeParse(input);
351
if (!result.success) {
352
result.error.issues.forEach((issue) => {
353
switch (issue.code) {
354
case z.ZodIssueCode.invalid_type:
355
console.log(`Expected ${issue.expected}, got ${issue.received}`);
356
break;
357
case z.ZodIssueCode.too_small:
358
console.log(`Value too small: minimum is ${issue.minimum}`);
359
break;
360
case z.ZodIssueCode.custom:
361
console.log(`Custom validation failed: ${issue.message}`);
362
break;
363
}
364
});
365
}
366
367
// Pattern 5: Form validation
368
function validateForm(formData: FormData) {
369
const result = FormSchema.safeParse(
370
Object.fromEntries(formData.entries())
371
);
372
373
if (!result.success) {
374
const errors = result.error.flatten().fieldErrors;
375
// Display errors in form
376
return { success: false, errors };
377
}
378
379
return { success: true, data: result.data };
380
}
381
382
// Pattern 6: API response
383
async function handleRequest(body: unknown) {
384
const result = await schema.safeParseAsync(body);
385
386
if (!result.success) {
387
return {
388
status: 400,
389
errors: result.error.format(),
390
};
391
}
392
393
return {
394
status: 200,
395
data: result.data,
396
};
397
}
398
```
399
400
## Custom Error Messages
401
402
```typescript
403
// Custom error messages
404
const schema = z
405
.string()
406
.min(5, "Too short!")
407
.max(20, "Too long!");
408
409
// Error map for all issues
410
const customSchema = z.string().parse(data, {
411
errorMap: (issue, ctx) => {
412
if (issue.code === z.ZodIssueCode.too_small) {
413
return { message: "Custom message for too_small" };
414
}
415
return { message: ctx.defaultError };
416
},
417
});
418
419
// Global error map
420
z.config({
421
errorMap: (issue, ctx) => {
422
// Custom global error mapping
423
return { message: ctx.defaultError };
424
},
425
});
426
```
427