skip to content

A request to your API is syntactically valid JSON but fails a business rule — for example an end date before the start date. Would you answer with HTTP status 400 or 422, and how do you draw the line between them in a contract?

level: middleimportance: must knowfreq 56%

answer

  1. 400 = can't parse/bind
  2. 422 = parsed fine, rules refuse it
  3. 415 wrong Content-Type, 413 too large
  4. 409 = conflicts with current state
  5. Problem Details + stable machine code + field errors

basics

~20 s

400 for a request the server cannot parse or that is malformed — bad JSON, wrong type, missing required field. 422 for a well-formed request whose content violates semantic rules. Both are client errors; consistency and a machine-readable error body matter more than the choice.

solid answer

~50 s

The distinction is **can I understand it** versus **can I accept it**. - **400 Bad Request** — malformed syntax or a request the server cannot process at all: invalid JSON, a string where a number is required, an unparseable query parameter, a missing required field. - **422 Unprocessable Content** — the syntax is fine and the fields are the right types, but the meaning is invalid: `endDate` before `startDate`, an IBAN that fails checksum, a state transition that is not allowed from the current state. In practice many APIs use 400 for everything and put the detail in the body, which is defensible — clients rarely branch on 400 versus 422, they read the error payload. What is not defensible is mixing them arbitrarily. Whichever line you draw, return a structured body (RFC 9457 `application/problem+json` is a good default) with a stable error code and per-field details, because that is what clients actually program against.

go deeper

for a junior

Say 400 means the server could not understand the request and 422 means it understood but the values break a rule; both are the client's fault.

for a middle

Give concrete examples on each side, mention 415 and 413, and describe a structured error body with per-field detail.

for a senior

Argue for a single enforced policy, stable error codes clients can depend on, and dashboards that separate client errors from server errors.

for a principal

Define the platform error contract — envelope format, code registry, ownership of the taxonomy — so aggregating clients handle every service identically.

## Two different failures When a client sends something wrong, there are two distinguishable situations: 1. **The server cannot interpret the request.** The JSON does not parse; a field declared as an integer contains `"abc"`; a required field is missing so no domain object can be constructed. Nothing about the business is involved — the request never becomes meaningful data. 2. **The server understood the request perfectly and refuses it.** All types check out, the object was constructed, and then a rule said no: the date range is inverted, the discount exceeds the order total, the account is closed so it cannot be charged. `400 Bad Request` covers the first. `422 Unprocessable Content` (renamed from "Unprocessable Entity" in RFC 9110, originally from WebDAV) was defined exactly for the second: the request is well-formed and the content type is understood, but the instructions cannot be followed. ## Where the line actually falls The boundary is fuzzier than it looks, and that is why teams disagree. - *Missing required field* — usually 400 (the object cannot be built), but if your validation layer builds the object and then checks presence, 422 is equally arguable. - *Wrong enum value* — 400 if you treat it as a type error, 422 if you treat it as a domain rule. - *Field too long* — length is a constraint on meaning, so 422 fits, but frameworks commonly emit 400. Because of this, the pragmatic rule is: **pick a policy and enforce it in one place.** Two policies work well. **Policy A (two codes).** 400 for parse/bind failures, 422 for validation failures. This is what many framework defaults naturally produce once a validation library is wired in, and it gives operators a useful split: 400 spikes mean a client is sending garbage (often a deploy or a serialization bug), 422 spikes mean users are hitting a rule. **Policy B (one code).** 400 for all client-side input problems, with the body carrying the detail. Simpler to explain, and honest about the fact that most clients do not branch on the code. Note that 422 is not a wire-level oddity — it is a normal status and any HTTP client handles it — so the argument against it is convention, not compatibility. What is genuinely wrong is having no policy: the same class of failure returning 400 from one service and 422 from another makes error handling in an aggregating client miserable. ## The body is the real contract A status code is one integer; clients need more. Use a structured error format — RFC 9457 Problem Details (`application/problem+json`) is the standard one: ``` HTTP/1.1 422 Unprocessable Content Content-Type: application/problem+json { "type": "https://example.com/probs/validation", "title": "Validation failed", "status": 422, "code": "DATE_RANGE_INVALID", "errors": [ {"field": "endDate", "code": "BEFORE_START", "message": "endDate must be after startDate"} ] } ``` Key properties: a **stable machine code** clients can branch on (never the human message — that gets reworded and translated), **field-level detail** so a UI can highlight inputs, and **all failures at once** rather than one per round trip. Avoid leaking internals: no stack traces, no SQL, no "user 4711 not found in table users". ## Related codes that get confused with these - **415 Unsupported Media Type** — the `Content-Type` itself is one you do not accept (client sent XML, you take JSON). Not 400. - **413 Content Too Large** — body exceeds your limit. Not 400 or 422. - **409 Conflict** — the request is valid but conflicts with current state (duplicate unique key, concurrent modification). The distinction from 422 is whether the problem is *inherent to the request* (422) or *relative to current state* (409). - **404** — the addressed resource does not exist, as opposed to a field inside the body being wrong. ## Operational angle Because 4xx means "the client can fix this", these codes should generally **not** page anyone and should **not** be retried by the client. Make sure your dashboards separate 4xx from 5xx, and watch for the inversion where a server bug is reported as 400 — that hides real outages behind a "client error" label, and it is one of the more common ways an incident goes unnoticed for hours.

  • Is 422 safe to use, given it came from WebDAV?
    Yes. RFC 9110 lists 422 Unprocessable Content as a general HTTP status, and any conforming client treats an unknown 4xx as a generic client error anyway, so there is no compatibility risk. The real argument is consistency: if your platform has standardized on 400 for all input errors, adding 422 in one service is worse than the theoretical purity is worth.
  • What should the error response body contain?
    A stable machine-readable code that clients branch on, a human-readable message for logs and developers, and field-level entries so a UI can mark the offending inputs — ideally all failures in one response rather than one per round trip. Use a standard envelope such as RFC 9457 problem+json, and never include stack traces, SQL, or internal identifiers, since 4xx bodies are attacker-visible.

saying these in an interview costs you the question

  • Returning 200 with a validation-errors payload
  • Using 500 for a request the client sent wrong
  • Branching client logic on the human-readable error message instead of a stable code
  • Mixing 400 and 422 for the same class of failure across endpoints
  • Leaking stack traces or SQL into 4xx error bodies

context