409 Conflict: When a Request Clashes With Current State
Status 409 Conflict means your request was understood but collides with the current state of the thing it targets. Typical cases are creating a user or file that already exists, saving over a newer version someone else wrote, or pushing a stale revision. Refresh the state, resolve the clash, then resend.
| Service or case | What clashed | Usual fix |
|---|---|---|
| Sign-up or create API | Email or username already taken | Show a clear message or switch to update |
| Optimistic locking | Version number older than the stored one | Reload, merge changes, retry |
| Kubernetes API | resourceVersion changed since you read it | Get the object again and reapply |
| Cloud storage buckets | Bucket name already in use or not empty | Pick another name or empty it first |
| CouchDB documents | Missing or old _rev | Fetch the latest _rev and resend |
Updated
Unlike 400, the request is well formed. It would have worked a moment earlier or with different data. That makes 409 a signal to look at state on the server, not at syntax, and usually means the client needs to read before it writes again.
Send and handle 409
Map a unique constraint to 409 in Express
23505 is Postgres unique_violation; other databases use their own codes.
try {
await db.query("INSERT INTO users(email) VALUES ($1)", [email]);
res.status(201).end();
} catch (err) {
if (err.code === "23505") {
return res.status(409).json({ error: "Email already registered", field: "email" });
}
throw err;
}React to 409 on the client
Reload the latest copy instead of retrying the same body.
const res = await fetch(url, { method: "PUT", body, headers });
if (res.status === 409) {
const latest = await fetch(url).then((r) => r.json());
showConflict(latest);
}
Handling 409 in a client
Treat 409 as a branch in your code, not a crash. For duplicates, show the user what already exists. For edit conflicts, load the server copy and either merge automatically or show both versions so a person can pick.
Collaborative editors and form tools avoid lost updates exactly this way: the save carries the version you started from, and the server refuses it when someone else saved in between.
Returning 409 from your own API
Catch the database's unique constraint error, such as Postgres code 23505, and map it to 409 with a message naming the field. Letting it bubble up turns a predictable clash into a 500.
If all you need is a business site rather than an API with conflict rules, We.Inc can build and publish it without any of this server code.
How it works
- Read the response body, which normally names the field or version that clashed.
- Fetch the current version of the resource.
- Decide whether to merge, overwrite deliberately, or ask the user.
- Resend the request with the new version or changed data.
Tips
- Retrying a 409 unchanged in a loop never helps. Unlike 429 or 503, the conflict will still be there.
- If you design an API, send 409 for duplicates and version clashes and include which field conflicted, so clients can show a useful message.
- With ETags, send If-Match on updates; servers commonly answer a stale one with 412 Precondition Failed rather than 409, so handle both.
- Double-clicked submit buttons often create a duplicate on the second request. Disable the button while the first request runs.
Frequently asked questions
What does a 409 response code mean?
It means Conflict: the server cannot complete the request because it conflicts with the target resource's current state. The client is expected to resolve the conflict and try again.
Is 409 a client or server error?
It is in the 4xx range, so it is a client error. The server is working; the request needs different data or a fresher version.
Should a duplicate email return 409 or 400?
409 is the common choice because the input is valid but clashes with existing data. Some teams use 422. Pick one and document it for API users.
How do I fix a 409 Conflict in Kubernetes?
The object changed after you read it. Get it again with kubectl get, apply your change to that fresh copy, and submit, or use kubectl apply, which handles merging for you.
Related: HTTP status codes, 400 Bad Request, 429 Too Many Requests, GraphQL mutations.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
More in Guides
- 500 Internal Server Error: Finding the Real Cause
- 502 Bad Gateway: Meaning and Fixes
- 503 Service Unavailable: Meaning, Causes and Fixes
- 504 Gateway Timeout: What Timed Out and How to Fix It
- Abandoned Cart Email Examples and Templates
- Abandoned Cart Text Messages
- About Us Page Examples: 6 Annotated Designs for Small Businesses | How-to Guide
- How to Accept Payments on a Website
Product
Who It's For
- For Agencies
- For Freelancers
- For Hosting Providers
- For SaaS Platforms
- For Startups
- For Financial Services
- For Healthcare
Features
Resources
- Blog
- Help Center
- Free Business Tools
- Free UI Components
- Website Templates
- Template Collections
- Website Examples
- Guides
- Comparisons
- Alternatives
- Best Lists
- Reviews
- Pricing Guides
- Use Cases
- Glossary & Guides
- Integrations
- Developers
- Benchmark
- Windows App