HTTP
428 - Precondition Required
Getting a 428 Precondition Required means the server requires conditional headers (If-Match, If-None-Match, If-Modified-Since, If-Unmodified-Since) but your request doesn't include them—the server enforces optimistic concurrency control and won't process requests without version checks. This client-side error (4xx) happens when servers mandate conditional requests to prevent lost updates. Most common when updating resources without ETag validation, but also appears when servers require If-Match for all modifications, delete operations need conditional headers, or security policies enforce version checks.
#Common Causes
- →Frontend: Missing If-Match header for PUT/PATCH requests. No If-None-Match for create operations. Conditional headers not included in delete requests. ETag not retrieved before update.
- →Backend: Server middleware requires conditional headers for all modifications. Security policy enforces optimistic locking. Resource versioning mandates conditional requests. Server configuration requires If-Match for updates.
- →Infrastructure: API gateway enforces conditional header requirements. Load balancer strips conditional headers. Reverse proxy doesn't pass If-Match headers. WAF blocks requests without conditional headers.
✓Solutions
- 1Step 1: Diagnose - Check DevTools Network tab Request Headers—verify if If-Match or If-None-Match headers are present. Review server response for Precondition-Required header. Check if ETag was retrieved first.
- 2Step 2: Diagnose - Server logs show which conditional header is missing. Review server configuration for precondition requirements. Check if middleware is enforcing conditional requests. Verify infrastructure header handling.
- 3Step 3: Fix - Client-side: Get resource ETag first with GET request. Include If-Match header with ETag value for updates. Add If-None-Match: * for create operations. Retry with conditional headers if 428 occurs.
- 4Step 4: Fix - Server-side: Return 428 with Precondition-Required header listing needed headers. Provide clear error messages about required conditions. Configure middleware to require conditional headers.
- 5Step 5: Fix - Infrastructure: Ensure load balancer passes conditional headers. Configure reverse proxy to preserve If-Match headers. Update API gateway to allow conditional headers. Review WAF rules.
</>Code Examples
Fetch API: Handle 428 with Conditional Headers
1// Client-side: Handle 428 by adding required conditional headers
2async function updateResource(id, data) {
3 // First, get resource to retrieve ETag
4 const getResponse = await fetch(`/api/resources/${id}`);
5
6 if (getResponse.status === 428) {
7 // Server requires conditional headers even for GET
8 const preconditionRequired = getResponse.headers.get('Precondition-Required');
9 throw new Error(`Precondition required: ${preconditionRequired}`);
10 }
11
12 const etag = getResponse.headers.get('ETag');
13
14 if (!etag) {
15 throw new Error('ETag not found in response');
16 }
17
18 // Update with If-Match header
19 const updateResponse = await fetch(`/api/resources/${id}`, {
20 method: 'PUT',
21 headers: {
22 'Content-Type': 'application/json',
23 'If-Match': etag, // Required conditional header
24 },
25 body: JSON.stringify(data),
26 });
27
28 if (updateResponse.status === 428) {
29 // Precondition required - check which header is needed
30 const preconditionRequired = updateResponse.headers.get('Precondition-Required');
31 throw new Error(`Precondition required: ${preconditionRequired}`);
32 }
33
34 if (updateResponse.status === 412) {
35 // Precondition failed - ETag mismatch
36 throw new Error('Resource was modified by another request');
37 }
38
39 return updateResponse.json();
40}
41
42// For create operations, use If-None-Match
43async function createResource(data) {
44 const response = await fetch('/api/resources', {
45 method: 'POST',
46 headers: {
47 'Content-Type': 'application/json',
48 'If-None-Match': '*', // Prevents overwriting existing resources
49 },
50 body: JSON.stringify(data),
51 });
52
53 if (response.status === 428) {
54 throw new Error('Precondition required for create operation');
55 }
56
57 return response.json();
58}Express.js: Require Conditional Headers
1// Server-side: Enforce conditional headers
2const express = require('express');
3const app = express();
4
5// Middleware to require conditional headers for modifications
6const requireConditionalHeaders = (req, res, next) => {
7 const method = req.method;
8
9 // Require conditional headers for PUT, PATCH, DELETE
10 if (['PUT', 'PATCH', 'DELETE'].includes(method)) {
11 const hasIfMatch = req.headers['if-match'];
12 const hasIfNoneMatch = req.headers['if-none-match'];
13 const hasIfModifiedSince = req.headers['if-modified-since'];
14 const hasIfUnmodifiedSince = req.headers['if-unmodified-since'];
15
16 if (!hasIfMatch && !hasIfNoneMatch && !hasIfModifiedSince && !hasIfUnmodifiedSince) {
17 return res.status(428)
18 .set('Precondition-Required', 'If-Match, If-None-Match')
19 .json({
20 error: 'Precondition Required',
21 message: 'This operation requires conditional headers (If-Match or If-None-Match)',
22 required: ['If-Match', 'If-None-Match'],
23 });
24 }
25 }
26
27 next();
28};
29
30// Apply to all routes
31app.use('/api/resources', requireConditionalHeaders);
32
33// Update endpoint
34app.put('/api/resources/:id', async (req, res) => {
35 const etag = req.headers['if-match'];
36 const resource = await db.resources.findById(req.params.id);
37
38 if (!resource) {
39 return res.status(404).json({ error: 'Resource not found' });
40 }
41
42 // Verify ETag matches
43 if (etag && etag !== resource.etag) {
44 return res.status(412).json({ error: 'Precondition Failed' });
45 }
46
47 const updated = await db.resources.update(req.params.id, req.body);
48 res.set('ETag', updated.etag).json(updated);
49});Nginx: Pass Conditional Headers
1# Nginx: Ensure conditional headers reach backend
2server {
3 listen 80;
4 server_name api.example.com;
5
6 location /api/ {
7 proxy_pass http://backend;
8 proxy_set_header Host $host;
9 proxy_set_header X-Real-IP $remote_addr;
10
11 # Pass conditional headers to backend
12 proxy_set_header If-Match $http_if_match;
13 proxy_set_header If-None-Match $http_if_none_match;
14 proxy_set_header If-Modified-Since $http_if_modified_since;
15 proxy_set_header If-Unmodified-Since $http_if_unmodified_since;
16
17 # Don't strip conditional headers
18 proxy_pass_request_headers on;
19 }
20}↗Related Errors
Provider Information
This error code is specific to HTTP services. For more information, refer to the official HTTP documentation.