409 Client Error 📋

409 Conflict: State Conflicts and Optimistic Locking

Last updated: June 28, 2026 • 6 min read

✦ The Golden Answer: The 409 Conflict status code indicates that the request could not be completed because it conflicts with the current state of the resource. This is commonly used in versioning and optimistic locking scenarios — for example, when a client tries to update a resource using an outdated ETag, and the resource has been modified by another client in the meantime. It is also used when trying to create a resource that already exists (e.g., duplicate email address). The client should retrieve the latest state of the resource and retry the request with the updated information.

Common Causes of 409 Conflicts

CauseExampleHow to Fix
Optimistic locking failurePUT request with If-Match header using an outdated ETag.GET the latest version, merge changes, and retry with new ETag.
Duplicate resource creationPOST to create a user with an email that already exists.Inform the client; they must choose a different identifier or update the existing resource.
State transition conflictTrying to cancel an order that is already shipped.Check the current state and only allow valid transitions.
Concurrent editsTwo clients editing the same document simultaneously.Use a merge strategy or reject the second edit with 409.
Dependency conflictsDeleting a parent resource that has child resources.Either delete children first or allow cascading deletes.

Example: Optimistic Locking with ETag

A client attempts to update a resource, but the server detects that the resource has been modified since the client last fetched it:

PUT /api/users/123 HTTP/1.1 Host: example.com If-Match: "abc123" Content-Type: application/json {"name": "John Updated"} HTTP/1.1 409 Conflict Content-Type: application/json { "error": "Resource has been modified by another user", "current_etag": "xyz789", "current_version": "v2" }

The client should GET the latest version, merge its changes, and retry with the new ETag.

409 vs. 412 Precondition Failed

  • 412 Precondition Failed – the server does not meet the client's preconditions (e.g., If-Match fails). The server returns 412 before attempting to apply the request.
  • 409 Conflict – the server attempted the request but encountered a conflict with the current state. The conflict may be resolved by the client (e.g., by fetching the latest state and retrying).

In practice, 409 is more common in optimistic locking scenarios because it gives the client more context about the conflict.

When to Use 409

  • PUT or PATCH – when the client sends an update based on a stale version.
  • POST – when the client tries to create a resource that already exists (duplicate key).
  • DELETE – when the resource cannot be deleted because it's referenced by other resources.
  • State transitions – when the current state of the resource does not allow the requested operation.

How to Handle 409 on the Client

  1. Retrieve the current state of the resource (e.g., GET the latest version).
  2. Inspect the conflict information returned in the response body (if available).
  3. Merge your changes with the latest state, resolving any conflicts.
  4. Resend the request with an updated If-Match header or modified payload.

For duplicate creation, inform the user and suggest they use a different identifier or update the existing resource.

Frequently Asked Questions

Is 409 Conflict a client error or a server error?

It's a client error (4xx), because the client's request is based on an outdated state. The server is functioning correctly; it's the client that needs to adapt.

Can 409 be used for validation errors?

No, 409 is for state conflicts, not validation. For validation errors (e.g., invalid email format, missing required field), use 422 Unprocessable Entity.

Should I retry automatically on a 409?

Only if you can resolve the conflict automatically (e.g., by merging changes). If a human decision is required, you should inform the user and let them decide how to proceed.