Last Updated: 3/12/2026
Error Handling
When validation fails, Zod provides detailed error information to help you understand what went wrong and communicate issues to users.
Throwing Errors with .parse()
The .parse() method throws a ZodError when validation fails:
import * as z from "zod";
const User = z.object({
username: z.string(),
age: z.number(),
});
try {
User.parse({ username: 123, age: "25" });
} catch (err) {
if (err instanceof z.ZodError) {
console.log(err.issues);
/* [
{
code: 'invalid_type',
expected: 'string',
received: 'number',
path: ['username'],
message: 'Expected string, received number'
},
{
code: 'invalid_type',
expected: 'number',
received: 'string',
path: ['age'],
message: 'Expected number, received string'
}
] */
}
}Safe Parsing with .safeParse()
To avoid try/catch blocks, use .safeParse(). It returns a result object with a success property:
const result = User.safeParse({ username: 123, age: "25" });
if (!result.success) {
// Validation failed
console.log(result.error.issues);
} else {
// Validation succeeded
console.log(result.data);
}The result is a discriminated union , so TypeScript automatically narrows the type based on success.
Error Structure
Each issue in ZodError.issues contains:
code— The error type (e.g.,invalid_type,too_small,invalid_string)path— The path to the invalid field (e.g.,['user', 'email'])message— A human-readable error message- Additional properties — Vary by error code (e.g.,
expected,received,minimum,maximum)
Formatting Errors
Zod provides helpers to format errors for display:
const result = User.safeParse({ username: 123, age: "25" });
if (!result.success) {
// Flatten errors into a simple object
const formatted = result.error.flatten();
console.log(formatted.fieldErrors);
/* {
username: ['Expected string, received number'],
age: ['Expected number, received string']
} */
}Async Validation
If your schema uses async refinements or transforms, use .parseAsync() or .safeParseAsync():
const schema = z.string().refine(async (val) => {
// Async validation logic
return val.length <= 8;
});
await schema.parseAsync("hello"); // ✓
await schema.parseAsync("verylongstring"); // ✗ throws ZodError
const result = await schema.safeParseAsync("hello");
// => { success: true, data: "hello" }What’s Next
- Type Inference — Extract TypeScript types from your schemas
- Common Patterns — Work with optional, nullable, and default values