When building REST APIs, handling duplicate resource creation (such as attempting to register an email address that already exists) often sparks debate over whether to return HTTP 409 Conflict or HTTP 422 Unprocessable Content.

Both status codes indicate client-side errors on well-formed requests, but they convey distinct architectural meanings.

Core distinction: state collision versus input validation

  • HTTP 409 Conflict: Use when the operation cannot be completed because it directly clashes with the current state of a resource on the server (e.g., a record with the same unique identifier already exists).
  • HTTP 422 Unprocessable Content: Use when the submitted payload is treated as failing validation rules (e.g., the input payload as a whole violates semantic constraints).

Neither approach violates HTTP semantics; the choice depends on how your API models resource state versus input validation.

What HTTP 409 Conflict means

According to RFC 9110, an HTTP 409 Conflict status indicates that the request could not be completed due to a conflict with the current state of the target resource.

Status 409 is primarily used in scenarios where the user may be able to resolve the conflict and resubmit the request:

  • Unique constraint violations: Attempting to POST /v1/users with an email address already registered.
  • Optimistic concurrency collisions: Attempting a PUT request with an outdated If-Match ETag header when another client has already modified the resource.
  • State machine conflicts: Attempting to cancel an order that has already transitioned to shipped state.
HTTP/1.1 409 Conflict
Content-Type: application/json

{
  "error": "resource_conflict",
  "message": "A user with email 'alex@example.test' already exists.",
  "conflicting_field": "email"
}

What HTTP 422 Unprocessable Content means

An HTTP 422 Unprocessable Content response means the server understands the content type and the syntax of the request is correct, but the instructions cannot be processed.

In APIs that treat uniqueness as a field-level validation rule (similar to checking field length or format), the server treats the duplicate field as an unprocessable instruction:

HTTP/1.1 422 Unprocessable Content
Content-Type: application/json

{
  "error": "validation_failed",
  "fields": {
    "email": "Email has already been taken"
  }
}

State collisions vs. payload validation

The distinction comes down to how the server categorizes the error:

  1. State collision (409): The payload itself is perfectly valid in isolation; it only fails because of the existing data state in the database.
  2. Payload validation (422): The server validation pipeline bundles uniqueness checks alongside format checks into a unified validation error structure.

Side-by-side comparison table

Feature HTTP 409 Conflict HTTP 422 Unprocessable Content
Primary Meaning Clashes with existing server state Fails semantic processing or validation
Common Trigger Duplicate unique keys, ETag version mismatch Invalid field values, business rule violations
Client Action Refresh current state, resolve collision Correct invalid fields in payload
RFC Reference RFC 9110 Section 15.5.10 RFC 9110 Section 15.5.21

How to choose the right status code in your API

When defining API conventions:

  • Choose 409 Conflict: If you want client libraries to explicitly distinguish between “your input format is bad” (400/422) and “this resource already exists / state conflict” (409). This is especially useful for optimistic locking, version control, and dedicated resource endpoints.
  • Choose 422 Unprocessable Content: If your frontend forms consume unified validation error responses where uniqueness is returned as a field-level error alongside regex or required-field failures.

What to check before changing code

  1. Does the API documentation define 409 or 422 for uniqueness constraint violations?
  2. Does your frontend or API client have dedicated conflict resolution logic for 409 responses?
  3. Are state conflicts returning informative JSON bodies describing the colliding identifier?

Key takeaway

Use HTTP 409 Conflict when an operation fails because of a clash with current server state (such as duplicate unique entities or concurrent edit collisions). Use HTTP 422 Unprocessable Content when the failure is handled as a semantic form validation error.