Валидация в Zod строится вокруг строгого описания схем и
детализированного описания ошибок, возникающих при несоответствии
входных данных этим схемам. Центральным объектом механизма ошибок
является ZodError, который агрегирует все проблемы
валидации в унифицированной форме.
Каждая ошибка внутри ZodError представлена как
ZodIssue и содержит стандартизированную структуру:
code — тип ошибки (invalid_type,
too_small, unrecognized_keys и т.д.)path — путь к полю, где произошла ошибкаmessage — человекочитаемое описаниеexpected, received, minimum,
maximum и т.д.)Пример структуры:
{
issues: [
{
code: "invalid_type",
expected: "string",
received: "number",
path: ["user", "name"],
message: "Expected string, received number"
}
]
}
Zod предоставляет два основных способа выполнения валидации:
Метод parse выбрасывает исключение при первой же ошибке
валидации:
schema.parse(data)
При ошибке генерируется ZodError, который необходимо
обрабатывать через try/catch:
try {
schema.parse(data)
} catch (err) {
if (err instanceof ZodError) {
// обработка ошибок
}
}
Метод safeParse возвращает структурированный результат
без исключений:
const result = schema.safeParse(data)
Форма результата:
{
success: true,
data: ...
}
или
{
success: false,
error: ZodError
}
Такой подход позволяет централизованно обрабатывать ошибки без использования исключений:
const result = schema.safeParse(data)
if (!result.success) {
const issues = result.error.issues
}
Поле issues в ZodError является основным
источником информации для диагностики ошибок. Оно содержит все найденные
несоответствия, включая вложенные структуры.
Каждый элемент массива содержит path, который отражает
маршрут до проблемного поля:
[
{
path: ["user", "address", "zip"],
message: "Invalid zip code"
}
]
Путь строится как массив ключей и индексов, что позволяет точно локализовать ошибку даже в сложных структурах:
["user", "profile", "email"]["items", 2, "price"]Метод format() преобразует ZodError в
древовидную структуру, удобную для UI-отображения:
const formatted = error.format()
Пример результата:
{
user: {
name: {
_errors: ["Required"]
}
}
}
Особенности:
_errors содержит массив сообщенийМетод flatten() преобразует ошибки в две группы:
const flat = error.flatten()
Результат:
{
formErrors: [],
fieldErrors: {
name: ["Required"],
email: ["Invalid email"]
}
}
Использование:
formErrors — ошибки уровня всей формыfieldErrors — ошибки конкретных полейТакой формат часто применяется в UI-библиотеках, где требуется простая мапа поле → ошибка.
Каждый ZodIssue содержит код, позволяющий
классифицировать ошибку:
Основные типы:
invalid_typetoo_smalltoo_biginvalid_stringunrecognized_keysinvalid_unioncustomПример обработки:
for (const issue of error.issues) {
switch (issue.code) {
case "invalid_type":
// обработка типа
break
case "too_small":
// обработка минимального значения
break
}
}
При работе с объектами и массивами Zod сохраняет точный путь до каждой ошибки. Например:
const schema = z.object({
user: z.object({
posts: z.array(
z.object({
title: z.string()
})
)
})
})
Ошибка может выглядеть так:
{
path: ["user", "posts", 0, "title"],
message: "Required"
}
Это позволяет однозначно определить проблемный элемент даже в глубоко вложенных структурах.
При использовании z.union() ошибки становятся
агрегированными, так как проверяются несколько альтернативных схем.
const schema = z.union([
z.string(),
z.number()
])
При несоответствии всех вариантов формируется
invalid_union:
{
code: "invalid_union",
unionErrors: [ZodError, ZodError]
}
Каждая альтернатива содержит собственный набор issues,
что позволяет диагностировать, почему каждая ветка не подошла.
Метод superRefine позволяет добавлять собственные ошибки
в процессе валидации:
z.object({
password: z.string()
}).superRefine((data, ctx) => {
if (data.password.length < 8) {
ctx.addIssue({
code: "custom",
message: "Too short",
path: ["password"]
})
}
})
Контекст ctx предоставляет:
addIssue() — добавление ошибкиЭто основной механизм для бизнес-валидации, выходящей за рамки стандартных проверок типов.
Zod позволяет централизованно изменять сообщения об ошибках:
z.setErrorMap((issue, ctx) => {
return { message: "Ошибка валидации" }
})
Параметры:
issue — текущая ошибкаctx — контекст с дефолтным сообщениемИспользуется для:
Механизм setErrorMap часто применяется для многоязычных
систем:
z.setErrorMap((issue) => {
const messages = {
invalid_type: "Неверный тип данных",
too_small: "Значение слишком маленькое"
}
return {
message: messages[issue.code] ?? "Ошибка"
}
})
В серверной логике ZodError часто преобразуется в
стандартизированный HTTP-ответ:
return {
success: false,
errors: error.issues.map(i => ({
field: i.path.join("."),
message: i.message
}))
}
Результат:
{
"success": false,
"errors": [
{
"field": "user.email",
"message": "Invalid email"
}
]
}
Такой формат удобен для фронтенда и не зависит от внутренней структуры Zod.
При работе с формами часто требуется преобразование ошибок в плоскую структуру:
const errors = Object.fromEntries(
error.issues.map(issue => [
issue.path.join("."),
issue.message
])
)
Результат:
{
"user.name": "Required",
"user.email": "Invalid email"
}
При последовательной проверке нескольких схем можно агрегировать ошибки:
const resultA = schemaA.safeParse(data)
const resultB = schemaB.safeParse(data)
if (!resultA.success || !resultB.success) {
const combined = [
...(resultA.success ? [] : resultA.error.issues),
...(resultB.success ? [] : resultB.error.issues)
]
}
Это полезно при составных моделях данных или multi-step валидации.
По умолчанию Zod собирает все ошибки, не прерывая проверку после первой. Это поведение обеспечивает:
Однако при использовании parse с abortEarly
(в некоторых конфигурациях окружения) возможно изменение поведения на
“первая ошибка”.
Поле path является ключевым элементом для интеграции с
UI и state-менеджерами. Оно позволяет:
Пример маршрутизации:
setFieldError(issue.path.join("."), issue.message)
При использовании .strict() Zod генерирует ошибку
unrecognized_keys:
{
code: "unrecognized_keys",
keys: ["extraField"]
}
Это важно для систем, где требуется жёсткий контракт данных (API, микросервисы, конфигурации).
ZodError также поддерживает доступ к полному объекту
ошибок без преобразований:
error.issueserror.nameerror.messageerror.stack (в runtime)Это позволяет интегрировать Zod в системы логирования и мониторинга, сохраняя полную трассировку валидации.