nextcloud/server · error · Sabre\DAV\Exception
An error occurred while checking content
Error message
An error occurred while checking content
What it means
Thrown by MultipartRequestParser::isAt() when fread() on the DAV request body returns false while peeking ahead for the multipart boundary. The bulk-upload parser must read and then seek back on the body stream, so any stream that cannot be read at the current cursor aborts with this generic Sabre\DAV\Exception. Note that isAtLastBoundary() runs in the while-condition of BulkUploadPlugin::httpPost, OUTSIDE its try/catch, so this escapes as an unhandled HTTP 500 instead of the endpoint's usual 400 JSON reply.
Source
Thrown at apps/dav/lib/BulkUpload/MultipartRequestParser.php:101
if (trim($boundaryKey) !== 'boundary') {
throw new BadRequest('Boundary is invalid');
}
return $boundaryValue;
}
/**
* Check whether the stream's cursor is sitting right before the provided string.
*
* @throws Exception
*/
private function isAt(string $expectedContent): bool {
$expectedContentLength = strlen($expectedContent);
$content = fread($this->stream, $expectedContentLength);
if ($content === false) {
throw new Exception('An error occurred while checking content');
}
$seekBackResult = fseek($this->stream, -$expectedContentLength, SEEK_CUR);
if ($seekBackResult === -1) {
throw new Exception('Unknown error while seeking content', Http::STATUS_INTERNAL_SERVER_ERROR);
}
return $expectedContent === $content;
}
/**
* Check whether the stream's cursor is sitting right before the boundary.
*/
private function isAtBoundary(): bool {
return $this->isAt($this->boundary);
}
/**View on GitHub (pinned to ecdeb153ff)
Solutions
- Reproduce with a known-good payload (curl or the Nextcloud desktop client) to rule out malformed multipart data
- Check the server log for the stack trace and identify which component touched $request->getBody() before OCA\DAV\BulkUpload\BulkUploadPlugin::httpPost
- Ensure nothing consumes the body earlier in the request lifecycle, or rewind it / rewrap it in a php://temp buffer before the bulk endpoint parses it
- If the stream resource is closed or invalid, fix the code that created or replaced the request body so a readable resource reaches the parser
Example fix
// before $raw = stream_get_contents($request->getBody()); // body consumed; later fread() in isAt() fails // after $body = $request->getBody(); rewind($body); // let MultipartRequestParser read from the start
Defensive patterns
Strategy: try-catch
Validate before calling
$body = $request->getBody();
if (!is_resource($body) || !is_readable($body)) {
throw new BadRequest('Request body is not a readable stream');
}
if (!feof($body)) {
rewind($body); // ensure parser starts at the beginning
} Try / catch
// BulkUploadPlugin calls isAtLastBoundary() OUTSIDE its try/catch - wrap it too:
try {
while (!$parser->isAtLastBoundary()) {
[$headers, $content] = $parser->parseNextPart();
}
} catch (Sabre\DAV\Exception $e) {
$this->logger->error($e->getMessage());
$response->setStatus(500);
return false;
} Prevention
- Never consume $request->getBody() in earlier plugins without rewinding it
- Wrap non-seekable/unreliable bodies in a php://temp buffer before the bulk endpoint parses them
- Log stream metadata (seekable, readable) when the bulk endpoint fails to speed up diagnosis
When it happens
Trigger: POST to /dav/bulk where the Sabre request body is unreadable at the cursor: the body stream was already consumed or closed by an earlier plugin/handler, a broken stream wrapper was set as body, or the client aborted mid-upload so the underlying socket read fails.
Common situations: Middleware or another Sabre plugin reading the body before the bulk plugin and not rewinding it; tests injecting a closed resource as body; flaky connections dropping during large multi-file uploads.
Related errors
- Fail to read part's content.
- 500
- Boundary not found where it should be.
- An error occurred while reading headers of a part
- 400
AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17).
Data as JSON: /api/errors/6ab6dde1b4420ba1.
Report an issue: GitHub.