# Semantic rejections answer 422

A body that parses but breaks a rule now answers `422` with a code and populated `details`, not an empty `400`.

Aug 21, 2026 · Improved

A body that parses but breaks a rule now answers `422` with a code and populated `details`, instead of `400` with an empty `details` object. `400` is left for what is wrong with the request target.

## What else changed

- **The split, stated once.** `400` means the fault is in the request target — an unknown query parameter, a malformed identifier in the path. `422` means the body is syntactically valid but semantically wrong. Several rejections were on the wrong side of that line and have moved.
- **`details` is no longer empty.** A rejection now names the field and the rule: which value was rejected, which field it depends on, which values are allowed. Before, the reason was buried in the message text — readable by a person, useless to code.
- **Where you will notice it.** Enabling a default without enabling the feature it depends on, a date range that runs backwards or exceeds the maximum, an identifier that is required and arrived blank. All of these used to be `400` with `details: {}`.
- **If you branch on the status code**, check that you are not treating `422` as a transport error. If you branch on `error.code` you are already fine: the codes did not change, they were simply not reachable before.

---

Full OpenAPI spec: https://docs.beel.es/api/openapi