428 Precondition Required
The origin server requires the request to be conditional.
Usually happens because:
- ☑ Client attempts write operations (PUT/DELETE)
🔍 Quick Checklist:
Meaning
The HTTP 428 Precondition Required client error status code indicates that the origin server requires the request to be conditional (e.g. carrying If-Match or If-None-Match headers). This protects against 'lost update' conflicts.
Root Causes
- Client attempts write operations (PUT/DELETE) without conditional headers (If-Match) on resources where concurrency locks are enforced.
| Cause | Frequency |
|---|---|
| Client attempts write operations (PUT/DELETE) | ⭐⭐⭐⭐⭐ |
Common Mistakes
- Using 412 Precondition Failed when the header is *missing* (use 428 when the header is missing; use 412 when the header is present but evaluates to false).
How to Fix
Framework-Specific Examples
Express middleware enforcing conditional checks.
app.put('/api/data', (req, res, next) => {
if (!req.headers['if-match']) {
return res.status(428).json({ error: 'If-Match header required' });
}
next();
});Server Configuration Examples
Nginx forwards conditional headers downstream.
# Forwarded downstreamPrevention
- Enforce concurrency checks inside REST documentation pipelines.
Frequently Asked Questions (FAQ)
Q: Why did HTTP introduce the 428 status code?
To prevent the 'lost update' problem, where client A fetches a file, client B fetches it too, B edits and saves, and then A saves, overwriting B's changes silently. Enforcing conditional If-Match headers resolves this.
Q: What is the difference between 428 and 412?
428 Precondition Required means the client *forgot* to send conditional headers. 412 Precondition Failed means the client *sent* headers, but the conditions evaluated to false (e.g. resource was modified by someone else).
Q: Is 428 cacheable?
No. The 428 Precondition Required status code is never cached.
Q: What is the recommended recovery action for clients on 428?
Issue a GET request to obtain the current resource representation and its ETag header, copy the ETag hash, and resend the request with an 'If-Match' header.