Multi-Status
ActiveHTTP 207 Multi-Status indicates the message body contains a DAV:multistatus XML document with multiple response codes for independent sub-operations. Defined in RFC 4918 §11.1 (WebDAV). The 207 itself does NOT indicate success — clients must parse individual DAV:response elements to determine per-resource outcomes.
Description
The 207 Multi-Status response provides status for multiple independent operations within a single request. Unlike most HTTP status codes that describe a single outcome, 207 is a container — the actual successes and failures live inside the response body as individual status codes per resource.
The response body MUST be an XML document with a DAV:multistatus root element. Each DAV:response child element contains a DAV:href identifying the affected resource and a DAV:status or DAV:propstat element carrying that resource's individual HTTP status code. A single 207 response might contain a mix of 200, 403, 404, 423, and 424 status codes for different resources touched by one request.
This is a critical distinction from normal HTTP semantics: a 207 response does NOT mean everything succeeded. It means 'I processed multiple things — here are the individual results.' A naive client that sees '2xx' and assumes success will miss failures buried inside the body. Every consumer of 207 must parse the body and handle per-item status codes independently.
The status code originated in WebDAV (RFC 4918) for operations like PROPFIND on collections, COPY/MOVE of directory trees, and batch property updates. When you ask a WebDAV server to copy a folder with 50 files, some might succeed, some might fail due to permissions, and some might be locked — 207 reports all of these in one response.
Modern REST APIs have adopted the pattern for batch operations. Microsoft Graph API, some Salesforce endpoints, and various internal service APIs return 207 when processing arrays of items where each can independently succeed or fail. The body format varies — some use the original WebDAV XML, others use JSON arrays with per-item status fields — but the semantics are identical: the outer status code is a container, not a verdict.
Examples
PROPFIND /webdav/project/ HTTP/1.1
Host: dav.example.com
Depth: 1
Content-Type: application/xml
Authorization: Bearer token123
<?xml version="1.0" encoding="utf-8"?>
<D:propfind xmlns:D="DAV:">
<D:prop>
<D:getcontentlength/>
<D:getlastmodified/>
<D:resourcetype/>
</D:prop>
</D:propfind>HTTP/1.1 207 Multi-Status
Content-Type: application/xml; charset=utf-8
<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>/webdav/project/</D:href>
<D:propstat>
<D:prop>
<D:resourcetype><D:collection/></D:resourcetype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>/webdav/project/report.pdf</D:href>
<D:propstat>
<D:prop>
<D:getcontentlength>2048576</D:getcontentlength>
<D:getlastmodified>Mon, 15 Jan 2024 10:00:00 GMT</D:getlastmodified>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>/webdav/project/secret.docx</D:href>
<D:propstat>
<D:prop/>
<D:status>HTTP/1.1 403 Forbidden</D:status>
</D:propstat>
</D:response>
</D:multistatus>POST /api/v1/messages/batch-delete HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer admin-token
{"ids": ["msg_001", "msg_002", "msg_003", "msg_004"]}HTTP/1.1 207 Multi-Status
Content-Type: application/json
{"results": [{"id": "msg_001", "status": 200, "message": "Deleted"}, {"id": "msg_002", "status": 200, "message": "Deleted"}, {"id": "msg_003", "status": 404, "message": "Message not found"}, {"id": "msg_004", "status": 423, "message": "Message is locked by retention policy"}]}HTTP/1.1 207 Multi-Status
Content-Type: application/xml; charset=utf-8
<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>/webdav/dest/file1.txt</D:href>
<D:status>HTTP/1.1 201 Created</D:status>
</D:response>
<D:response>
<D:href>/webdav/dest/file2.txt</D:href>
<D:status>HTTP/1.1 423 Locked</D:status>
<D:error><D:lock-token-submitted/></D:error>
</D:response>
<D:response>
<D:href>/webdav/dest/file3.txt</D:href>
<D:status>HTTP/1.1 424 Failed Dependency</D:status>
</D:response>
</D:multistatus>Edge Cases
- •207 does NOT mean success — a response where every inner status is 4xx or 5xx is still wrapped in a 207. Clients MUST parse the body to find actual outcomes.
- •If ALL sub-operations fail with the same error, the server MAY return that error directly (e.g., 403) instead of wrapping in 207. Only use 207 when results genuinely vary.
- •424 Failed Dependency frequently appears INSIDE a 207 body — it signals that a sub-operation failed because another sub-operation it depended on already failed (cascade failure).
- •The Depth header in WebDAV PROPFIND controls whether 207 returns results for just the target (Depth: 0), immediate children (Depth: 1), or the entire subtree (Depth: infinity).
- •Non-WebDAV APIs using 207 for batch operations often use JSON instead of XML, but the semantic contract is identical: outer code = container, inner codes = verdicts.
- •A 207 response body can be extremely large for deep collection operations — clients should stream-parse rather than buffering the entire response before processing.
- •Some proxies and CDNs may cache 207 responses incorrectly because they treat all 2xx as cacheable successes. Use Cache-Control: no-store when 207 responses contain mutable or per-user data.
When You'll See This
- →WebDAV PROPFIND retrieving properties of all files in a folder — some accessible, some permission-denied
- →COPY or MOVE of a collection where some destination resources are locked by other users
- →Batch API deleting 20 items where 3 are not found, 2 are locked, and 15 succeed
- →Microsoft Graph batch endpoint processing 10 API calls — mix of successes and rate-limited failures
- →CalDAV/CardDAV syncing multiple calendar events or contacts where some have conflicts
- →Bulk permission update on a file tree where some files have inherited locks
- →PROPPATCH setting multiple properties on a resource — some writable, some read-only
Implementation References
| Language | Constant |
|---|---|
| Go | http.StatusMultiStatus |
| Rust | http::StatusCode::MULTI_STATUS |
| Python | http.HTTPStatus.MULTI_STATUS |
| Node.js | http.STATUS_CODES[207] |
| .NET | HttpStatusCode.MultiStatus |
| Java | 207 (no built-in constant; use SC_MULTI_STATUS in WebDAV libs) |
| PHP | Response::HTTP_MULTI_STATUS (Symfony) |
| Ruby | :multi_status (Rack) |
History
Introduced in RFC 2518 (1999) as part of the original WebDAV specification by Jim Whitehead and Yaron Goland. The problem it solved: HTTP's single-status-per-response model broke down when a single request (like COPY of a directory tree) affected dozens of resources that could independently succeed or fail. RFC 4918 (2007) revised and updated the WebDAV specification, retaining 207 with clarified semantics. The concept migrated beyond WebDAV as batch APIs became common — Microsoft's Graph API (2015+) adopted 207 for batch request endpoints, establishing a pattern that other cloud APIs followed. The status code remains registered under IANA's HTTP Status Code Registry referencing RFC 4918.
Related Status Codes
Related Headers
FAQ
Does a 207 Multi-Status response mean the request succeeded?
No. 207 is a container, not a verdict. It means the server processed multiple sub-operations and is reporting their individual results. The outer 207 tells you nothing about success or failure — you must parse the response body and inspect each DAV:response element (or JSON item in modern APIs) for its individual status code. A 207 could contain all 200s (everything worked), all 4xxs (everything failed), or any mix. Treating 207 as 'success' without parsing the body is a common and dangerous client bug.
What is the relationship between 207 Multi-Status and 424 Failed Dependency?
424 Failed Dependency is a status code designed to appear INSIDE a 207 response body. When a batch operation has dependencies between sub-operations (e.g., copying a file requires the parent directory to exist), and an earlier sub-operation fails, dependent sub-operations receive 424 to indicate they weren't attempted because their prerequisite failed. For example: if copying /dir/file.txt fails because /dir/ couldn't be created (403), then file.txt gets 424. This cascade-failure signaling prevents clients from retrying items that would always fail until the root cause is fixed.
Can I use 207 Multi-Status for non-WebDAV batch REST APIs?
Yes, and many production APIs do. Microsoft Graph API uses 207 for its $batch endpoint, returning JSON with per-request status codes. The key requirement: your response body must clearly identify each sub-operation and its individual outcome. Use JSON with an array of result objects, each containing an identifier, status code, and optional error detail. Document that clients must parse per-item results — do not let consumers assume the outer 207 means success. Consider whether your batch is truly independent-per-item (use 207) or all-or-nothing transactional (use a single status code with rollback).