affaan-m/ECC · error
VALIDATION_ERROR
VALIDATION_ERROR
Error message
Request validation failed
What it means
This is the ZodError branch of the handleApiError helper shown in the error-handling skill: when a Next.js route validates its request body with a Zod schema and parsing fails, the handler returns HTTP 422 with code VALIDATION_ERROR and a details array mapping each failing field path to its message. It exists so clients get actionable, field-level feedback instead of a generic 400.
Source
Thrown at skills/error-handling/SKILL.md:138
if (error instanceof AppError) {
return NextResponse.json(
{
error: {
code: error.code,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
},
{ status: error.statusCode },
)
}
// Zod validation error
if (error instanceof z.ZodError) {
return NextResponse.json(
{
error: {
code: 'VALIDATION_ERROR',
message: 'Request validation failed',
details: error.issues.map(i => ({
field: i.path.join('.'),
message: i.message,
})),
},
},
{ status: 422 },
)
}
// Unexpected error — log details, return generic message
console.error('Unexpected error:', error)
return NextResponse.json(
{ error: { code: 'INTERNAL_ERROR', message: 'An unexpected error occurred' } },
{ status: 500 },
)
}View on GitHub (pinned to d8409a4b08)
Solutions
- Read response.error.details[] — each entry names the exact field path and the failing constraint; fix those fields in the request payload
- Compare the payload against the route's Zod schema (it is the source of truth for the contract)
- If you own the API and just added the field, make it optional or give it a default so older clients keep working
- Validate on the client with the same (shared) schema before sending to fail early with better UX
Example fix
// before - client sends body missing a required field
await fetch('/api/users', { method: 'POST', body: JSON.stringify({ email: 'a@b.co' }) })
// -> 422 { code: 'VALIDATION_ERROR', details: [{ field: 'name', message: 'Required' }] }
// after
await fetch('/api/users', { method: 'POST', body: JSON.stringify({ email: 'a@b.co', name: 'Ada' }) }) Defensive patterns
Strategy: validation
Validate before calling
// Server-side: use safeParse and branch before it can throw
const parsed = CreateUserSchema.safeParse(await req.json())
if (!parsed.success) {
return NextResponse.json(
{ error: { code: 'VALIDATION_ERROR', message: 'Request validation failed', details: parsed.error.issues } },
{ status: 422 },
)
}
// parsed.data is now fully typed for the handler Type guard
const isZodError = (e: unknown): e is z.ZodError => e instanceof z.ZodError
Try / catch
try {
await handler(req)
} catch (error) {
if (error instanceof z.ZodError) {
// 422 with field-level details from error.issues — never rethrow raw
return respond422(error.issues.map(i => ({ field: i.path.join('.'), message: i.message })))
}
throw error // let the generic 500 branch log it Prevention
- Share the exact Zod schema module between client and server so the contract cannot drift
- Validate on the client with safeParse before sending and show field errors in the form
- Read details[].field from 422 responses programmatically instead of string-matching messages
- When adding required fields to a schema, ship them as .optional() or with .default() first to avoid breaking existing clients
When it happens
Trigger: POSTing a body that fails the route's Zod schema: missing required field, wrong type (string where number expected), invalid email format, string shorter than a min() constraint, or a nested object whose sub-field fails (reported as dotted paths like 'address.street').
Common situations: Frontend and backend schema drift after a new required field was added server-side; enum value typo from a hand-written curl; JSON key casing mismatch (createdAt vs created_at); empty string sent where min(1) applies; API consumer built against an older version of the contract.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- INTERNAL_ERROR
- Invalid ECC repo root: missing package.json at ${packageJson
- Invalid ECC repo root: missing install script at ${installAp
- Invalid ECC repo root: unreadable package.json at ${packageJ
- Invalid mode "${mode}". Allowed modes: ${allowedModes.join('
AI-assisted analysis of affaan-m/ECC@d8409a4b08 (2026-08-26).
Data as JSON: /api/errors/6a754ef71b37db3e.
Report an issue: GitHub.