Skip to content
stateless.co · Engineering notes from the request/response layer
statelessThe engineering desk

A publication about the machinery under everyday software: the contracts between services, the queries behind a page, and the failures that only show up in production.

01APIs & Protocols

409 vs 422: When to Use Which Status Code for a Rejected Request

As a developer, you've likely hit a code review where two hardworking colleagues spar over which HTTP status code to return for a rejected request. Is it 409 (Conflict) or 422…

409 vs 422: When to Use Which Status Code for a Rejected Request
Photo: Thamizhpparithi Maari · CC BY-SA 3.0 · Wikimedia Commons
What is in this piece
  1. The Governing Rule
  2. 409: State Conflicts, Not Syntax Errors
  3. 422: Valid Syntax, Bad Meanings
  4. 400, 404 and Other options for request failures
  5. Common examples:

The Governing Rule

The core decision hinges on whether the request failed due to:

  • Malformed syntax: One of the syntactic parts was entered improperly as per the API's norms.
  • Invalid but perfectly formed semantics: The syntax is right, but trying to process that payload never ends well.
  • Conflict with existing state: The client's actions are totally kosher, but your resource is shaking its head at this initiative.

For all-but-core-HTTP systems, the RFC 9110 lays the groundwork for defining these:

RFC 9110 defines these codes as follows:

  • 409 (Conflict): The request could not be completed due to a conflict with the current state of the target resource.
  • 422 (Unprocessable Content): The server understands the content type of the request, and the syntax of the request entity is correct, but the server is unable to process the contained instructions.

RFC 9110 provides an XML example to illustrate 422:

"For example, the server might include an XML request element that contained semantically incorrect, imbalanced, or contradictory information so that the server could not process it..."

409: State Conflicts, Not Syntax Errors

A 409 doesn't mean your request is inherently flawed. It means your API is shaking its head at your current demand, saying, "No can do - not today!"

RFC 9110 is point blank:

"This status code indicates that the request could not be completed due to a conflict with the current state of the target resource."

IANA reaffirms this, citing the same RFC section:

"Conflict with current state of the resource. The server should send back any information about the conflict situation."

In contrast, RFC 4918, the original specification for 422, only defines "Unprocessable Entity" as, "The request was well-formed but was unable to be followed due to semantic errors."

MDN summarizes 422 as:

"The server understands the content type of the request entity (hence, it is syntactically correct), but is unable to process the contained instructions."

422: Valid Syntax, Bad Meanings

A 422 is for sane requests that can't be completed.

Your semantics need help, not your syntax. MDN says, in no uncertain terms, that a 422 is just that – a syntactically correct but semantically invalid client error:

"Unlike the 400 Bad Request message, a 422 response explicitly informs the client about the specific cause of validation failure."

It's for requests with correct syntax but semantic problems.

400, 404 and Other options for request failures

A rule of thumb for the cases is: 400 for malformed syntax, 422 for semantically valid but still meaningless instructions, 409 where state conflicts trip you up, and 404 for resources you can't find. 422 definition, what puts some request failures in 402, 404, etc.

Common examples:

That said, let's put these first-class citizens in the spotlight. We're likely all familiar with those 422 favorite: validation errors.

A write request's payload might pass muster for form and order, but fail for quantity or quality. required might be required but not delivered. An email address might be shipshape but not deliverable. Your schema may call for a version number, but get an empty string. Charge attempts might squeeze past but fail the preliminary fraud checks. Each of these examples is what 422/409 originally said

In each case, your API doesn't flag an outright syntax error, but it still can't process the offending request.

Similarly, if a user is trying to write a new payment method but their account is locked, their identity is unverified, or they hold insufficient funds, it's also a valid but rejected request.

When it comes to 409, an example might be a user trying to upsert a duplicate resource. Your workspace might have a unique email constraint — but the new upload's email is already in use. It's a well-formed call, but you reject it due to a resource-level conflict. Confirm 409 rule as you said, vs 422 as written

And so it goes. In each case, you reject a well-formed but useless API request. But putting a 409 or 422 on a disagreement might mean differentiating between whether the rejection was due to the resource state, or due to the semantics of the request – but not its syntax.