What HTTP 428 means (and what it is asking for)

HTTP status code 428 stands for “Precondition Required.” It indicates that the server refuses to process the request because it requires specific precondition information—usually expressed via conditional request headers—before it can safely proceed.

In plain terms: the server wants you to prove something about the resource (for example, that you’re updating the correct version) or to satisfy a rule about whether the current state matches your expectation. Without those preconditions, the server blocks the operation.

How 428 works in practice (the request–response logic)

A 428 response is typically part of a safer update or concurrency control mechanism. Many workflows use conditional headers to prevent conflicts such as “lost updates” (where two clients overwrite each other’s changes).

While the exact required headers depend on the server and the endpoint, the general pattern is:

  1. You send a request to a resource (often with a method like PUT/PATCH/DELETE or another state-changing method).
  2. The server checks whether you included the conditional headers it expects.
  3. If the expected precondition is missing or doesn’t meet the server’s requirements, the server returns 428.
  4. Your client must resend the request including the correct precondition headers so the server can validate the resource state.

Common limitations and why you can’t “just retry”

1) 428 is not a generic temporary failure

A retry without changes usually won’t help because 428 is specifically about missing or unacceptable precondition data. Retrying the same request is likely to repeat the same block.

2) The required precondition can vary by endpoint

Different servers (and even different routes on the same server) may require different conditional headers or rules. That means a “working” precondition header set from one API operation may not work for another.

3) Method and payload shape matter

Even with the right headers, some servers also expect the request to use the appropriate HTTP method and to target the correct resource representation. If you send a mismatched method (e.g., a read-only method where the server expects an update precondition) you may still get 4xx errors.

  • 400 Bad Request: usually means the request is malformed or invalid in general. 428 more narrowly signals that preconditions are required for processing.
  • 412 Precondition Failed: often appears when you did send conditional headers, but the resource state didn’t satisfy the conditions. In contrast, 428 commonly means the server wanted preconditions in the first place.
  • 409 Conflict: sometimes covers concurrency or state conflicts in server-specific ways. 428 is specifically tied to the idea of “precondition required,” not just conflict.

Because servers implement these codes with some variation, treat the exact behavior as server-dependent.

Practical checks to resolve 428

1) Confirm the exact request being sent

Check that you are using the correct URL, HTTP method, and (if relevant) request headers you believe you are adding. In debugging, it’s easy to “think” a header was included when it was not.

2) Inspect conditional headers explicitly

Look for conditional/precondition headers in your outgoing request. Depending on the server, these could include headers such as:

  • entity tag–based conditions (commonly via If-Match)
  • time-based conditions (often via If-Unmodified-Since)

If you don’t know which one is required, start by comparing against what the server expects in similar successful requests (or consult server documentation if available).

3) Ensure the precondition value matches the current resource state

If your request includes preconditions, verify that the values are consistent with the resource state you intend to modify. For example, if you’re using a version identifier like an ETag, it must correspond to the version the server considers current.

4) Check for proxies or middleware that rewrite requests

Some setups may remove or alter headers (including conditional ones). If a load balancer, API gateway, or middleware touches requests, the conditional headers you set client-side may not reach the application that enforces the precondition.

5) Verify you’re not sending the header with the wrong scope

Conditional headers must apply to the targeted resource. If you accidentally set preconditions for one representation but send the request to a different one, you may still fail.

  • Optimistic concurrency control: using preconditions to prevent overwriting changes made by others.
  • ETags and conditional requests: a common mechanism for “only update if the version hasn’t changed.”
  • Idempotency vs. preconditions: preconditions protect state, while idempotency is about safely repeating requests.

Evidence-based uncertainty handling

If you cannot determine which precondition header(s) the server requires, base your next step on observed behavior: compare failing requests (428) to any successful ones for the same endpoint, and inspect the raw outbound headers at the client and at the server boundary. Because the specific “required” precondition is server- and endpoint-dependent, treat any single guess as provisional until you confirm it in logs or request captures.