Reference guide · http-status · Published 2026-08-16 · 3 min read
HTTP 428 Precondition Required explained
HTTP 428 Precondition Required tells a client its request must include a precondition header to prevent a race. Learn when servers use 428 and how clients should respond.
- ·What 428 means
- ·Lost update problem
- ·Choosing preconditions
What 428 means
HTTP 428 Precondition Required is returned by a server when it wants a request to be made conditional, but the client did not include the required precondition. The server is saying: your request would have succeeded, but I refuse to apply it blindly because that could overwrite a newer version of the resource. Include a precondition header, such as If-Match or If-None-Match, and retry.
The status is a message about the request, not the resource's current state. It does not mean the resource is missing or the operation is impossible. It means the server policy demands that the client prove it is working from an up-to-date version.
Lost update problem
The reason a server requests a precondition is to prevent the lost update race. Consider two clients both about to edit the same record:
- Client A reads the resource at version 1.
- Client B reads the resource at version 1.
- Client A writes its changes; the resource becomes version 2.
- Client B writes its changes, silently overwriting A's work.
Without a precondition, B clobbers A and no one is told. If the server requires every write to carry If-Match: <etag-or-version>, then B's write sends a stale tag, the server returns 412 (or 428 first, telling B it must have sent a condition at all), and the conflict is surfaced to a human instead of overwritten silently.
This optimistic concurrency pattern is common in content management, collaborative documents, and APIs that store a mutable version.
Choosing preconditions
The two dominant preconditions are:
If-Match: apply the operation only if the current state matches the supplied entity tag. Used for safe updates.If-None-Match: apply only if the state does not match. Used for cache revalidation and to guard "create only if absent".
The status pair to understand together:
- 428 tells the client it should have sent a precondition and did not.
- 412 Precondition Failed tells the client it did send a precondition, but the condition was not true right now.
The flow a robust client should follow:
- Read the resource and capture its current entity tag.
- Send the mutation with
If-Match: <etag>. - If 412 comes back, re-read, surface the newer state, and ask the user how to resolve the conflict.
- If 428 comes back, treat it as "this endpoint demands a conditional request", retry with the precondition, and fix the client so it always sends one.
428 is a niche status. Practical sites rarely see it because most servers omit the requirement rather than enforce it, but it is the correct signal when you do enforce conditional writes. It belongs to the client error family, sits beside HTTP 412, and is the natural partner of HTTP 409 when a conflict must be reported instead of retried.