- Home
- HTTP Status Codes
- 423 Locked
Status Code
423 Locked
The resource is locked and cannot be accessed or modified. Learn about WebDAV locks and how to handle locked resources.
What is 423 Locked?
TL;DR: Resource is locked by another user or process and can’t be modified. Wait for lock to expire or contact the lock owner.
A 423 Locked status code means the resource you’re trying to access is currently locked and cannot be modified. Think of it like trying to edit a document that someone else has open with exclusive editing rights—you can view it, but you can’t make changes until they release the lock.
This status code is part of the WebDAV (Web Distributed Authoring and Versioning) extension and is used to prevent conflicting modifications in collaborative environments.
When Does This Happen?
You’ll see a 423 Locked response in these common situations:
1. Exclusive Write Lock
User A has exclusive lock on file
User B tries to modify → 423 Locked
2. WebDAV File Editing
Document checked out for editing
Another user tries to edit → 423 Locked
3. Administrative Lock
Resource locked by administrator
Regular user tries to modify → 423 Locked
4. Processing Lock
File being processed (e.g., virus scan, conversion)
User tries to access → 423 Locked (temporary)
5. Concurrent Edit Prevention
First user locks resource for editing
Second user attempts modification → 423 Locked
Example Responses
Basic WebDAV Lock:
HTTP/1.1 423 Locked
Content-Type: application/xml; charset=utf-8
Lock-Token: <urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4>
<?xml version="1.0" encoding="utf-8" ?>
<D:error xmlns:D="DAV:">
<D:lock-token-submitted>
<D:href>/documents/report.docx</D:href>
</D:lock-token-submitted>
</D:error>
```text
**With Lock Information:**
```http
HTTP/1.1 423 Locked
Content-Type: application/json
Lock-Token: <urn:uuid:a1b2c3d4-e5f6-4789-a012-3456789abcde>
X-Lock-Owner: alice@example.com
X-Lock-Timeout: 900
{
"error": "Resource Locked",
"message": "This resource is currently locked and cannot be modified",
"lock_details": {
"lock_token": "urn:uuid:a1b2c3d4-e5f6-4789-a012-3456789abcde",
"locked_by": "alice@example.com",
"locked_at": "2026-01-18T14:30:00Z",
"lock_timeout": 900,
"lock_expires_at": "2026-01-18T14:45:00Z",
"lock_type": "exclusive"
},
"action": "Wait for lock to expire or contact the lock owner"
}
Administrative Lock:
HTTP/1.1 423 Locked
Content-Type: application/json
X-Lock-Type: administrative
Retry-After: 3600
{
"error": "Resource Locked",
"message": "This resource is locked for administrative purposes",
"lock_type": "administrative",
"reason": "Security audit in progress",
"locked_until": "2026-01-18T18:00:00Z",
"contact": "admin@example.com"
}
```text
## Real-World Example
Imagine two team members trying to edit the same document simultaneously:
**User Alice Locks Document:**
```http
LOCK /documents/quarterly-report.docx HTTP/1.1
Host: webdav.example.com
Content-Type: text/xml
Depth: 0
Timeout: Second-900
<?xml version="1.0" encoding="utf-8" ?>
<D:lockinfo xmlns:D="DAV:">
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
<D:owner>alice@example.com</D:owner>
</D:lockinfo>
Response:
HTTP/1.1 200 OK
Lock-Token: <urn:uuid:abc-123-def-456>
Content-Type: application/xml
<?xml version="1.0" encoding="utf-8" ?>
<D:prop xmlns:D="DAV:">
<D:lockdiscovery>
<D:activelock>
<D:locktoken><D:href>urn:uuid:abc-123-def-456</D:href></D:locktoken>
<D:timeout>Second-900</D:timeout>
</D:activelock>
</D:lockdiscovery>
</D:prop>
User Bob Tries to Modify (Fails):
PUT /documents/quarterly-report.docx HTTP/1.1
Host: webdav.example.com
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
Content-Length: 45678
[Document content...]
Response:
HTTP/1.1 423 Locked
Content-Type: application/json
Lock-Token: <urn:uuid:abc-123-def-456>
X-Lock-Owner: alice@example.com
{
"status": 423,
"error": "Locked",
"message": "Document is locked by another user",
"details": {
"resource": "/documents/quarterly-report.docx",
"lock_token": "urn:uuid:abc-123-def-456",
"locked_by": "alice@example.com",
"locked_at": "2026-01-18T14:30:00Z",
"lock_expires_at": "2026-01-18T14:45:00Z",
"time_remaining": "14 minutes"
},
"actions": {
"wait": "Wait for lock to expire in 14 minutes",
"contact": "Contact alice@example.com to release lock",
"force_unlock": "Admins can force unlock at /admin/locks/abc-123-def-456"
}
}
```text
**User Bob with Valid Lock Token (Succeeds):**
```http
PUT /documents/quarterly-report.docx HTTP/1.1
Host: webdav.example.com
If: (<urn:uuid:abc-123-def-456>) ← Valid lock token
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
[Document content...]
Response:
HTTP/1.1 204 No Content
Lock-Token: <urn:uuid:abc-123-def-456>
423 vs Other Access Control Codes
| Code | Meaning | Cause | Can Retry? |
|---|---|---|---|
| 423 | Locked | Resource locked (temporary) | Yes, when unlocked |
| 403 | Forbidden | No permission (permanent) | No, need authorization |
| 401 | Unauthorized | Not authenticated | Yes, with credentials |
| 409 | Conflict | State conflict | Yes, after resolving |
Important Characteristics
Temporary vs Permanent:
423 Locked: Temporary restriction
- Resource is locked by another user/process
- Will become available when unlocked
- Usually has timeout
403 Forbidden: Permanent restriction
- User lacks permission
- Won't change without authorization change
Lock Types:
Exclusive Lock:
- Only lock holder can modify
- Others get 423 until lock released
Shared Lock:
- Multiple readers allowed
- Writers get 423
- Prevents writes, allows reads
WebDAV Lock Headers:
Lock-Token: <urn:uuid:lock-token-id>
Timeout: Second-3600
Depth: 0 or infinity
If: (<lock-token>) ← Required to modify locked resource
```text
## Common Mistakes
**❌ Using 423 for permission issues**
```http
HTTP/1.1 423 Locked ← Wrong! User lacks permission
Message: You don't have permission to access this resource
# Should be:
HTTP/1.1 403 Forbidden
Message: You don't have permission to access this resource
❌ Not providing lock information
HTTP/1.1 423 Locked
Content-Type: text/plain
Resource is locked. ← Unhelpful, no details about lock
```text
**❌ Not implementing lock timeout**
```http
LOCK /resource → Lock created with no timeout
(User closes browser, lock never released) ← Resource locked forever!
✅ Correct usage with full information
HTTP/1.1 423 Locked
Content-Type: application/json
Lock-Token: <urn:uuid:lock-id>
Retry-After: 900
{
"error": "Locked",
"lock_owner": "user@example.com",
"lock_expires_at": "2026-01-18T15:00:00Z",
"retry_after": 900
}
```text
## Best Practices
**Always Include Lock Details:**
```http
HTTP/1.1 423 Locked
Content-Type: application/json
Lock-Token: <urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4>
X-Lock-Owner: alice@example.com
Retry-After: 600
{
"error": "Resource Locked",
"message": "This resource is currently locked",
"lock": {
"token": "urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4",
"owner": "alice@example.com",
"type": "exclusive",
"scope": "write",
"created_at": "2026-01-18T14:30:00Z",
"expires_at": "2026-01-18T14:40:00Z",
"timeout_seconds": 600
},
"suggestions": [
"Wait for lock to expire",
"Contact lock owner to release",
"Try again after lock expiration"
]
}
Implement Lock Timeouts:
// Express.js example
const locks = new Map()
app.lock('/documents/:id', (req, res) => {
const docId = req.params.id
const timeout = parseInt(req.headers.timeout?.replace('Second-', '')) || 900
if (locks.has(docId)) {
return res.status(423).json({
error: 'Already locked',
lock: locks.get(docId)
})
}
const lockToken = `urn:uuid:${uuidv4()}`
const expiresAt = Date.now() + timeout * 1000
locks.set(docId, {
token: lockToken,
owner: req.user.email,
expiresAt
})
// Auto-remove lock after timeout
setTimeout(() => locks.delete(docId), timeout * 1000)
res.status(200).set('Lock-Token', `<${lockToken}>`).json({ lockToken, expiresAt })
})
app.put('/documents/:id', (req, res) => {
const docId = req.params.id
const providedToken = req.headers.if?.match(/<(.+)>/)?.[1]
const lock = locks.get(docId)
if (lock) {
if (lock.expiresAt < Date.now()) {
locks.delete(docId) // Lock expired
} else if (lock.token !== providedToken) {
return res.status(423).json({
error: 'Locked',
lock_owner: lock.owner,
lock_expires: new Date(lock.expiresAt)
})
}
}
// Proceed with update
updateDocument(docId, req.body)
res.status(204).send()
})
```javascript
**Provide Lock Management Interface:**
```javascript
// View active locks
app.get('/admin/locks', adminOnly, (req, res) => {
const activeLocks = Array.from(locks.entries()).map(([id, lock]) => ({
resource_id: id,
...lock,
expires_in_seconds: Math.max(0, (lock.expiresAt - Date.now()) / 1000)
}))
res.json({ locks: activeLocks })
})
// Force unlock (admin only)
app.delete('/admin/locks/:token', adminOnly, (req, res) => {
const token = req.params.token
for (const [id, lock] of locks.entries()) {
if (lock.token === token) {
locks.delete(id)
return res.json({ message: 'Lock removed', resource_id: id })
}
}
res.status(404).json({ error: 'Lock not found' })
})
WebDAV Lock Implementation
Creating a Lock:
LOCK /documents/report.docx HTTP/1.1
Host: webdav.example.com
Content-Type: text/xml
Depth: 0
Timeout: Second-3600
<?xml version="1.0"?>
<D:lockinfo xmlns:D="DAV:">
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
<D:owner>alice@example.com</D:owner>
</D:lockinfo>
```http
**Refreshing a Lock:**
```http
LOCK /documents/report.docx HTTP/1.1
Host: webdav.example.com
If: (<urn:uuid:lock-token>)
Timeout: Second-1800
Unlocking:
UNLOCK /documents/report.docx HTTP/1.1
Host: webdav.example.com
Lock-Token: <urn:uuid:lock-token>
```javascript
## Implementation Examples
**Node.js/Express:**
```javascript
const locks = new Map()
function checkLock(req, res, next) {
const resourceId = req.params.id
const lock = locks.get(resourceId)
if (!lock) return next()
if (lock.expiresAt < Date.now()) {
locks.delete(resourceId)
return next()
}
const providedToken = req.headers.if?.match(/<(.+)>/)?.[1]
if (lock.token !== providedToken) {
return res.status(423).json({
error: 'Locked',
lock_token: lock.token,
lock_owner: lock.owner,
expires_at: new Date(lock.expiresAt).toISOString()
})
}
next()
}
app.put('/files/:id', checkLock, (req, res) => {
// Update file
res.status(204).send()
})
Python/Django:
from django.http import JsonResponse
from django.utils import timezone
from datetime import timedelta
import uuid
locks = {}
def check_lock(view_func):
def wrapper(request, resource_id, *args, **kwargs):
lock = locks.get(resource_id)
if lock and lock['expires_at'] > timezone.now():
provided_token = request.META.get('HTTP_IF', '').strip('<>')
if lock['token'] != provided_token:
return JsonResponse({
'error': 'Locked',
'lock_owner': lock['owner'],
'expires_at': lock['expires_at'].isoformat()
}, status=423)
return view_func(request, resource_id, *args, **kwargs)
return wrapper
@check_lock
def update_resource(request, resource_id):
# Update resource
return JsonResponse({'status': 'updated'})
Try It Yourself
Visit our request builder to simulate locked resources:
- Set method to LOCK
- Set path to /webdav/document.docx
- Click Send request to create lock
- Try PUT to same resource without lock token
- See 423 response with lock details
Related Status Codes
- 403 Forbidden - Permission denied (permanent)
- 409 Conflict - Request conflicts with current state
- 412 Precondition Failed - Conditional request failed
- 507 Insufficient Storage - Server out of storage (WebDAV)
Frequently Asked Questions
What does 423 Locked mean?
A 423 error means the resource is currently locked and cannot be modified. This is primarily used in WebDAV for file locking during collaborative editing.
When is 423 Locked used?
It is used in WebDAV systems when a file is locked by another user, in version control systems during checkouts, or in collaborative editing to prevent conflicts.
How do I fix a 423 error?
Wait for the lock to be released, contact the user who holds the lock, or use the UNLOCK method in WebDAV to release the lock if you have permission.
What is the difference between 423 and 409?
423 means the resource is explicitly locked by a locking mechanism. 409 means there is a general conflict with resource state. 423 is for lock-based systems; 409 is for state conflicts.