Debug API Payload Schema Rejection
Reproduce a 422 payload rejection and use schema validation diagnostics to find the exact property path that fails.
Task
Use structured validation errors to pinpoint which field in a rejected request violates the API schema.
When to use this
An integration breaks after a client upgrade with a generic 422 and no field-level detail, blocking debugging.
Prerequisites
- A JSON schema or validator such as Zod or Ajv
- The failing request payload
- Access to the service logs
Steps
1. Emit structured validation errors keyed by JSON path.
const result = schema.safeParse(body);
if (!result.success) {
return res.status(422).json({
errors: result.error.issues.map(i => ({ path: i.path.join('.'), message: i.message })),
});
}Expected output: The response names the failing path such as items.0.price instead of a generic message.
2. Reproduce with the exact payload from logs.
curl -s -X POST https://api.example.com/v1/orders \
-H 'content-type: application/json' --data @failing.json | jq .errorsExpected output: The same field path is returned, confirming the violation is deterministic.
Troubleshooting
Problem
Validator accepts but business logic still rejects
Solution
Layer a domain validation step after schema validation so semantic errors are also specific.
Problem
Error message leaks internals
Solution
Return field paths and safe messages, never stack traces or schema dumps.
Limitations
- Schema validation cannot capture cross-field business rules.
- Over-detailed errors can help attackers; keep them field-scoped.
- Requires the validator to preserve element indices in arrays.
What this recipe does
Use structured validation errors to pinpoint which field in a rejected request violates the API schema.
An integration breaks after a client upgrade with a generic 422 and no field-level detail, blocking debugging.
Prerequisites
- A JSON schema or validator such as Zod or Ajv
- The failing request payload
- Access to the service logs
Procedure
- Emit structured validation errors keyed by JSON path.
const result = schema.safeParse(body);
if (!result.success) {
return res.status(422).json({
errors: result.error.issues.map(i => ({ path: i.path.join('.'), message: i.message })),
});
}
Expected result: The response names the failing path such as items.0.price instead of a generic message.
- Reproduce with the exact payload from logs.
curl -s -X POST https://api.example.com/v1/orders \
-H 'content-type: application/json' --data @failing.json | jq .errors
Expected result: The same field path is returned, confirming the violation is deterministic.
How to confirm it worked
Run the commands above and confirm every expected result in order. If a step does not produce the stated output, use the troubleshooting notes before continuing. A passing run shows a rejected payload returns the exact field path, and fixing that field makes the request return 200.
Troubleshooting
Validator accepts but business logic still rejects — Layer a domain validation step after schema validation so semantic errors are also specific.
Error message leaks internals — Return field paths and safe messages, never stack traces or schema dumps.
Limitations
- Schema validation cannot capture cross-field business rules.
- Over-detailed errors can help attackers; keep them field-scoped.
- Requires the validator to preserve element indices in arrays.