Conflict Errors
title: "Conflict Errors — Handling 409 and Duplicate Resource Issues" description: "409 Conflict errors occur when a request conflicts with the current state of the server, including duplicate resources, version conflicts, and state violations." date: 2026-06-28 lastmod: 2026-06-28 weight: 18 tags: [apis, error-handling] }
409 Conflict errors occur when a request can't be completed due to a conflict with the resource's current state, such as duplicate creation or stale version updates.
What You'll Learn
- When to use 409 Conflict
- Handling duplicate resources
- Optimistic locking with version conflicts
Why It Matters
Conflict errors prevent data corruption from concurrent modifications. Clear conflict responses help clients resolve the issue automatically.
Code Examples
// Duplicate resource error
{
"error": "CONFLICT",
"message": "A user with this email already exists",
"conflict_field": "email",
"conflict_value": "alice@example.com",
"existing_resource": "/users/42"
}
// Version conflict (optimistic locking)
{
"error": "CONFLICT",
"message": "Resource was modified since you last read it",
"expected_version": 5,
"current_version": 7,
"suggestion": "Re-fetch the resource and retry your update"
}
# Conflict error handling
class ConflictError(Exception):
def __init__(self, message, conflict_field=None, conflict_value=None):
self.message = message
self.conflict_field = conflict_field
self.conflict_value = conflict_value
@app.route('/users', methods=['POST'])
def create_user():
email = request.json.get('email')
existing = db.find_user_by_email(email)
if existing:
raise ConflictError(
"A user with this email already exists",
conflict_field="email",
conflict_value=email
)
@app.errorhandler(ConflictError)
def handle_conflict(error):
return jsonify({
"error": "CONFLICT",
"message": error.message,
"conflict_field": error.conflict_field,
"conflict_value": error.conflict_value
}), 409
# Optimistic locking for updates
@app.route('/users/<int:id>', methods=['PUT'])
def update_user(id):
user = db.get_user(id)
if user.version != request.json.get('expected_version'):
raise ConflictError(
"Resource modified since last read",
conflict_field="version"
)
Common Mistakes
1. Returning 400 Instead of 409
Duplicate resources and version conflicts are 409, not 400.
2. No Conflict Resolution Guidance
Tell clients how to resolve the conflict (re-fetch, use different value).
3. Not Including Current State
Show the current version or value so clients can decide how to proceed.
4. Race Conditions in Duplicate Checking
Check-then-insert has a race. Use unique constraints at the database level.
5. Silent Overwrites Without Conflict Detection
Always check for conflicts before updating. Silent overwrites lose data.
Practice Questions
- What status code indicates a conflict error?
- When should you use 409 over 400?
- How does optimistic locking work for API updates?
- What information should a conflict response include?
- How do you prevent race conditions in duplicate detection?
Answers:
- 409 Conflict.
- When the request conflicts with server state, not when input is malformed.
- Clients send the version they read; the server rejects if it changed.
- Conflict field, values, existing resource URL, and resolution guidance.
- Use database unique constraints instead of check-then-insert.
Challenge: Implement optimistic locking for a document editing API. Include version tracking, conflict detection, and automatic resolution suggestions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro