Utilo

HTTP 412 Precondition Failed – Free, Online, Private

412 Precondition Failed means a conditional header such as If-Match did not hold.

What HTTP 412 means

412 says the server evaluated a precondition and it failed, so the method was not applied. If-Match, If-None-Match, If-Unmodified-Since, and If-Modified-Since are the usual headers. This is optimistic concurrency: the client says 'only write if the ETag is still this', and 412 means someone else wrote first. The current state should be readable with a GET.

412 Precondition Failed belongs to the 4xx client error class. Clients that only look at the class will group it with its neighbors. Clients that care about the exact code should use the narrower rule on this page, because the class is only the first digit.

When you see HTTP 412

When you see HTTP 412 Precondition Failed, stop on that exact status line. 412 Precondition Failed means a conditional header such as If-Match did not hold. The trace that usually produces it: If-Match named an ETag that is no longer current. The 4xx client error class only tells you the first digit. A neighbor in that class is a different fault, and the fix on this page does not transfer to it.

Return 412 when a precondition header fails. Do not apply the write. Use 409 for conflicts that are not expressed as preconditions. Use 428 if you want to require a precondition the client forgot to send. 412 means a precondition was present and false.

How to fix HTTP 412

To fix HTTP 412, change the condition that made the server choose Precondition Failed. GET the current representation, reconcile, and retry with the new validator. Do not retry the failed precondition. You already know it is false. Retry only with an updated precondition. An immediate identical retry fails again. If the log line is a different code, leave this page. The mix-up people make with 412 is this one: 409 is a general state conflict. 428 means the precondition was required and absent. 304 means a conditional GET found no change. 412 means the method was not applied.

  • If-None-Match: * was sent and the resource already exists.
  • A client ignored 412 and overwrote the resource without a precondition.
  • The server compared a weak ETag as if it were strong and rejected a legal write.

An access log that only stores 412 is not enough to tell these apart. Keep the method, the path, and a request id. Do not keep the Authorization header or a request body that might be a token. The status explains the outcome. It is not a place to echo secrets back to the client either.

Example response

HTTP 412 Precondition FailedHTTP/1.1 412 Precondition Failed
ETag: "new"

The write did not happen. The ETag header can show the current tag, though clients should GET if they need the body. The request body was not applied. Tell the user someone else edited the document.

What the client should do

GET the current representation, reconcile, and retry with the new validator. Do not retry the failed precondition. You already know it is false.

Do not cache 412 as the resource. The GET that follows is the representation.

Retry only with an updated precondition. An immediate identical retry fails again.

Codes people confuse with HTTP 412

409 is a general state conflict. 428 means the precondition was required and absent. 304 means a conditional GET found no change. 412 means the method was not applied.

Frequently asked questions

Did the PUT happen?

No. A failed precondition means the method was not applied.

Which headers lead to 412?

If-Match, If-None-Match, If-Unmodified-Since, and If-Modified-Since, when the condition is false.

What should the client do?

Fetch the current resource and write again with the new ETag.

How is 428 different?

428 means the client should have sent a precondition and did not. 412 means it sent one and the check failed.

What should I do first when I see HTTP 412?

Read the status as 412 Precondition Failed specifically. 412 Precondition Failed means a conditional header such as If-Match did not hold. Then check the cause that matches the request you sent, starting with: If-Match named an ETag that is no longer current.