# HTTP 428 Precondition Required — Meaning, Causes & Fixes

> The server requires the request to be conditional, such as with If-Match, to prevent lost updates.

428 (RFC 6585) forces clients into safe concurrent editing. The server refuses unconditional writes: you must send `If-Match` with the ETag you last saw, so your update can't silently overwrite someone else's.

- Class: 4xx Client Error
- Retry: No — change the request first
- Cacheable by default: no
- Defined in: [RFC 6585 §3 — 428 Precondition Required](https://www.rfc-editor.org/rfc/rfc6585#section-3)

## Example response

```http
HTTP/1.1 428 Precondition Required
Content-Type: application/json
Content-Length: 33

{"error":"Precondition Required"}
```

## Common causes

- A PUT, PATCH or DELETE without `If-Match`, sent to an API that enforces optimistic concurrency.

## How to fix it

1. GET the resource, read its `ETag`, and send it as `If-Match` on the write.
2. Be ready to handle 412 if the resource changed in between.

## Send a 428 from your server

### Express

```
res.status(428).json({ error: "Precondition Required" });
```

### Next.js route handler

```
return Response.json({ error: "Precondition Required" }, { status: 428 });
```

### Flask

```
return {"error": "Precondition Required"}, 428
```

### Go net/http

```
http.Error(w, "Precondition Required", http.StatusPreconditionRequired)
```

### nginx

```
return 428;
```

## FAQ

### 428 vs 412?

428: you didn't send a precondition and the server requires one. 412: you sent one and it failed.

## Related status codes

- [412 Precondition Failed](https://www.devkult.com/http/412.md)
- [409 Conflict](https://www.devkult.com/http/409.md)
- [400 Bad Request](https://www.devkult.com/http/400.md)

Open the interactive page: https://www.devkult.com/http/428