{"record":{"id":"7d7052d9c6f88853","repo":"nextcloud/server","slug":"fail-to-read-part-s-content","errorCode":null,"errorMessage":"Fail to read part's content.","messagePattern":"Fail to read part's content\\.","errorType":"exception","errorClass":"Sabre\\DAV\\Exception","httpStatus":500,"severity":"error","filePath":"apps/dav/lib/BulkUpload/MultipartRequestParser.php","lineNumber":218,"sourceCode":"\n\t\treturn $headers;\n\t}\n\n\t/**\n\t * Return the content of a part of the multipart body.\n\t *\n\t * @throws Exception\n\t * @throws BadRequest\n\t */\n\tprivate function readPartContent(int $length): string {\n\t\tif ($length === 0) {\n\t\t\t$content = '';\n\t\t} else {\n\t\t\t$content = stream_get_line($this->stream, $length);\n\t\t}\n\n\t\tif ($content === false) {\n\t\t\tthrow new Exception(\"Fail to read part's content.\");\n\t\t}\n\n\t\tif ($length !== 0 && feof($this->stream)) {\n\t\t\tthrow new Exception('Unexpected EOF while reading stream.');\n\t\t}\n\n\t\t// Read '\\r\\n'.\n\t\tstream_get_contents($this->stream, 2);\n\n\t\treturn $content;\n\t}\n\n\t/**\n\t * Compute the MD5 or checksum hash of the next x bytes.\n\t * TODO: Drop $md5 argument when the latest desktop client that uses it is no longer supported.\n\t */\n\tprivate function validateHash(int $length, string $fileMd5Header, string $checksumHeader): void {\n\t\tif ($checksumHeader !== '') {","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/BulkUpload/MultipartRequestParser.php#L200-L236","documentation":"readPartContent() calls stream_get_line($this->stream, $length) with the part's declared Content-Length; a false return means the underlying read itself failed (distinct from a clean short read, which is caught by the EOF check instead). Thrown as a generic Exception; inside parseNextPart() BulkUploadPlugin catches it, logs it, and answers HTTP 400 with the JSON of files written so far.","triggerScenarios":"A hard read error on the request body stream at the part-content position: invalidated/closed resource, socket error, or stream wrapper failure while slurping the part bytes.","commonSituations":"Connection torn down mid-body with an RST; temp-file-backed body evicted or deleted under disk pressure; wrapper errors under memory limits.","solutions":["Check nextcloud.log for paired PHP I/O warnings at the same timestamp to identify the stream failure","Retry the bulk upload with fewer/smaller files to see whether the failure is size- or load-dependent","Fix whatever invalidated the stream resource (premature body close, temp file eviction, memory limit killing the wrapper)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"$body = $request->getBody();\nif (!is_resource($body) || !is_readable($body)) {\n    throw new \\RuntimeException('Request body stream is not readable');\n}","typeGuard":null,"tryCatchPattern":"try {\n    [$headers, $content] = $parser->parseNextPart();\n} catch (\\Exception $e) {\n    $this->logger->error($e->getMessage());\n    $response->setStatus(400);\n    $response->setBody(json_encode($writtenFiles, JSON_THROW_ON_ERROR));\n    return false;\n}","preventionTips":["Avoid reading the body resource from multiple components concurrently","Ensure temp files backing the body are not evicted mid-request (disk space)","Distinguish this hard-read-error from 'Unexpected EOF' which indicates truncation instead"],"tags":["php","webdav","nextcloud","bulk-upload","multipart","stream","io"],"backgroundTag":"stream-read-failure","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}