nextcloud/server · error · Sabre\DAV\Exception\BadRequest
Boundary not found where it should be.
Error message
Boundary not found where it should be.
What it means
readBoundary() first verifies the stream cursor sits exactly before '--<boundary>\r\n' (via isAtBoundary()); a mismatch throws Sabre\DAV\Exception\BadRequest (HTTP 400). It means the multipart payload structure desynchronized from the boundary declared in the Content-Type header.
Source
Thrown at apps/dav/lib/BulkUpload/MultipartRequestParser.php:158
$headers = $this->readPartHeaders();
$length = (int)$headers['content-length'];
$this->validateHash($length, $headers['x-file-md5'] ?? '', $headers['oc-checksum'] ?? '');
$content = $this->readPartContent($length);
return [$headers, $content];
}
/**
* Read the boundary and check its content.
*
* @throws BadRequest
*/
private function readBoundary(): string {
if (!$this->isAtBoundary()) {
throw new BadRequest('Boundary not found where it should be.');
}
return fread($this->stream, strlen($this->boundary));
}
/**
* Return the headers of a part of the multipart body.
*
* @throws Exception
* @throws BadRequest
* @throws LengthRequired
*/
private function readPartHeaders(): array {
$headers = [];
while (($line = fgets($this->stream)) !== "\r\n") {
if ($line === false) {
throw new Exception('An error occurred while reading headers of a part');View on GitHub (pinned to ecdeb153ff)
Solutions
- Byte-inspect the exact request (curl --trace-ascii, tcpdump) and compare the boundary after 'boundary=' in Content-Type with the '--<boundary>\r\n' markers in the body
- Ensure every part ends with \r\n and is followed by '--<boundary>\r\n', and the body ends with '--<boundary>--\r\n'
- Stop building the body by string concatenation; use a multipart library or the desktop client's payload as reference (see tests/unit .../MultipartRequestParserTest.php fixtures)
- Verify no intermediary proxy or input handler strips CR bytes
Example fix
// before (LF-only, wrong framing)
$body = "--$boundary\nContent-Length: 3\n\nfoo\n--$boundary--\n";
// after (exact CRLF framing the parser expects)
$body = "--$boundary\r\nContent-Length: 3\r\nX-File-MD5: " . md5('foo') . "\r\n\r\nfoo\r\n--$boundary--\r\n"; Defensive patterns
Strategy: validation
Validate before calling
// Client-side: assert the exact framing before sending
$marker = "--{$boundary}\r\n";
foreach ($parts as $i => $p) {
$body = $p['raw'];
if (!str_ends_with($body, "\r\n")) {
throw new \InvalidArgumentException("Part {$i} must end with CRLF before the next boundary");
}
} Try / catch
// Client side: inspect the 400 JSON body; parsing errors abort the whole upload
// HTTP 400 + {"<path>": ...} from /dav/bulk means framing was rejected - fix payload, do not retry as-is Prevention
- Use CRLF everywhere in multipart bodies; never \n
- Reuse the exact boundary token from Content-Type in every '--<boundary>' marker, unquoted
- Prefer a maintained multipart builder over string concatenation
When it happens
Trigger: POST to /dav/bulk where a part is not immediately followed by the exact boundary string: boundary in 'Content-Type: multipart/related; boundary=X' differs from the '--X\r\n' lines actually in the body, missing or extra CRLF between part content and the next boundary, LF-only line endings, or stray preamble bytes.
Common situations: Hand-rolled multipart writers using \n instead of \r\n; quoted or whitespace-padded boundary values handled differently by client and server; proxies rewriting line endings; copy-pasted example payloads with an edited boundary.
Related errors
- An error occurred while checking content
- An error occurred while reading headers of a part
- 400
- The Content-Length header must not be null.
- The hash headers must not be null.
AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17).
Data as JSON: /api/errors/13bcc6e9835ffbbb.
Report an issue: GitHub.