Which HTTP status code to use to reject a PUT due to optimistic locking failure

Oliver Drotbohm picture Oliver Drotbohm · Oct 1, 2013 · Viewed 9.2k times · Source

Assume I'd like to implement some kind of optimistic locking and use ETags to indicate the most up to date resource state. This means, clients will use an If-Match header when PUTting for an update.

According to the HTTP spec, the server has to return 412 Precondition failed if the ETag provided for the If-Match header doesn't match the current state of the resource.

However, 409 Conflict seems to be closer to what I want to express semantically, especially as it gives guidelines what to include in the response.

Is it terribly wrong to rather return 409 in case of a failure to match an ETag provided in an If-Match header?

Answer

user41871 picture user41871 · Oct 1, 2013

From your link to the spec:

If none of the entity tags match, or if "*" is given and no current entity exists, the server MUST NOT perform the requested method, and MUST return a 412 (Precondition Failed) response. This behavior is most useful when the client wants to prevent an updating method, such as PUT, from modifying a resource that has changed since the client last retrieved it.

Because the spec requires an HTTP 412 (indeed it uses "MUST"), and because it's clear that they accounted for precisely the use case under discussion, an HTTP 412 seems like the proper response code.

412 is pretty reasonable anyway. The request says to do the update conditionally. The 412 says that the condition failed, so the service won't do it. Especially since 412 is a good match for the concept of conditional requests; 409 would seem to attach to a specific sort of refusal, which may or may not be conditional in nature. For example, I could see a service returning a 409 in response to an unconditional request to POST something with an internal conflict.

But see the following, also from the spec:

10.4.10 409 Conflict

The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request. The response body SHOULD include enough information for the user to recognize the source of the conflict. Ideally, the response entity would include enough information for the user or user agent to fix the problem; however, that might not be possible and is not required.

Conflicts are most likely to occur in response to a PUT request. For example, if versioning were being used and the entity being PUT included changes to a resource which conflict with those made by an earlier (third-party) request, the server might use the 409 response to indicate that it can't complete the request. In this case, the response entity would likely contain a list of the differences between the two versions in a format defined by the response Content-Type.

Anyway the spec seems to require a 412 in conditional request contexts, while suggesting that version conflicts are a key driver for 409s. It might be that the 409 would be used where the version conflict occurs as part of an unconditional request.