← Recipes

阅读中文版本

Debug API Payload Schema Rejection

Reproduce a 422 payload rejection and use schema validation diagnostics to find the exact property path that fails.

~25 minapivalidationdebugging

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 .errors

Expected 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

  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 result: The response names the failing path such as items.0.price instead of a generic message.

  1. 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.