409 Conflict
Client Error - Request conflicts with current resource state
HTTP 409 Conflict
What It Means
The HTTP 409 Conflict status code indicates that the request could not be completed due to a conflict with the current state of the target resource. This is often resolvable by the user.
Common Scenarios
- Duplicate entry: Creating a user with an email that already exists
- Edit conflict: Two users editing the same document simultaneously
- Version mismatch: Optimistic locking detected stale data
- State conflict: Trying to publish an already-published post
- Delete conflict: Resource has dependent records
Example Responses
Duplicate email
HTTP/1.1 409 Conflict
Content-Type: application/json
{
"error": "Conflict",
"message": "A user with this email already exists",
"field": "email"
}
Edit conflict (optimistic locking)
HTTP/1.1 409 Conflict
Content-Type: application/json
{
"error": "Conflict",
"message": "Document was modified by another user",
"your_version": 3,
"current_version": 5
}
Optimistic Locking
Optimistic locking prevents lost updates by checking a version number before saving:
- Client fetches record with version=5
- Client edits and sends update with version=5
- Server checks: current version is now 6 (someone else edited)
- Server returns 409 Conflict
Implementation
Express.js - Duplicate check
app.post('/api/users', async (req, res) => {
const existing = await User.findOne({ email: req.body.email });
if (existing) {
return res.status(409).json({
error: 'Conflict',
message: 'Email already registered',
field: 'email'
});
}
// Create user...
});
Optimistic locking with version
app.put('/api/documents/:id', async (req, res) => {
const { version, content } = req.body;
const result = await db.query(
`UPDATE documents
SET content = ?, version = version + 1
WHERE id = ? AND version = ?`,
[content, req.params.id, version]
);
if (result.affectedRows === 0) {
return res.status(409).json({
error: 'Conflict',
message: 'Document was modified'
});
}
res.json({ success: true });
});
409 vs Other Codes
| Code | Use When |
|---|---|
| 409 | State conflict (duplicate, version mismatch) |
| 400 | Invalid request format/syntax |
| 422 | Valid format but semantic errors |
Best Practices
- Include details about what caused the conflict
- For edit conflicts, include both versions for merging
- Suggest resolution steps in the error message
- Use appropriate response body with conflict details