{"record":{"id":"49119ea4ebc04ebc","repo":"nextcloud/server","slug":"500","errorCode":"500","errorMessage":"Unknown error while seeking content","messagePattern":"Unknown error while seeking content","errorType":"exception","errorClass":"Sabre\\DAV\\Exception","httpStatus":500,"severity":"error","filePath":"apps/dav/lib/BulkUpload/MultipartRequestParser.php","lineNumber":106,"sourceCode":"\t\treturn $boundaryValue;\n\t}\n\n\t/**\n\t * Check whether the stream's cursor is sitting right before the provided string.\n\t *\n\t * @throws Exception\n\t */\n\tprivate function isAt(string $expectedContent): bool {\n\t\t$expectedContentLength = strlen($expectedContent);\n\n\t\t$content = fread($this->stream, $expectedContentLength);\n\t\tif ($content === false) {\n\t\t\tthrow new Exception('An error occurred while checking content');\n\t\t}\n\n\t\t$seekBackResult = fseek($this->stream, -$expectedContentLength, SEEK_CUR);\n\t\tif ($seekBackResult === -1) {\n\t\t\tthrow new Exception('Unknown error while seeking content', Http::STATUS_INTERNAL_SERVER_ERROR);\n\t\t}\n\n\t\treturn $expectedContent === $content;\n\t}\n\n\t/**\n\t * Check whether the stream's cursor is sitting right before the boundary.\n\t */\n\tprivate function isAtBoundary(): bool {\n\t\treturn $this->isAt($this->boundary);\n\t}\n\n\t/**\n\t * Check whether the stream's cursor is sitting right before the last boundary.\n\t */\n\tpublic function isAtLastBoundary(): bool {\n\t\treturn $this->isAt($this->lastBoundary);\n\t}","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/BulkUpload/MultipartRequestParser.php#L88-L124","documentation":"isAt() peeks at the stream with fread() and then rewinds with fseek($stream, -$length, SEEK_CUR); a -1 return means the body stream is not seekable and parsing cannot continue. The parser fundamentally requires a seekable body because it re-reads bytes for hash validation, so this surfaces as HTTP 500 (it escapes the plugin's try/catch via isAtLastBoundary()).","triggerScenarios":"POST to /dav/bulk where the Sabre\\HTTP request body is a non-seekable stream: php://input under SAPI configurations where it is not seekable, a socket/pipe, or a custom stream wrapper without seek support. Also hit when an earlier handler replaces the body with a pipe-like resource.","commonSituations":"Custom SAPI or CLI servers fronting DAV; stream wrappers that only support sequential access; exotic proxy setups that hand PHP a non-seekable body.","solutions":["Buffer the incoming body into a seekable stream (php://temp) before parsing and set it as the request body","Check which resource the webserver/SAPI hands to PHP for php://input in your setup; standard FPM/Apache setups are seekable, custom servers often are not","Inspect the stack trace to find which component supplied the non-seekable body and fix or wrap it"],"exampleFix":"// before\n$parser = new MultipartRequestParser($request, $logger); // body may be non-seekable -> fseek returns -1\n\n// after\n$src = $request->getBody();\nif (!stream_get_meta_data($src)['seekable']) {\n    $buf = fopen('php://temp', 'r+b');\n    stream_copy_to_stream($src, $buf);\n    rewind($buf);\n    $request->setBody($buf);\n}\n$parser = new MultipartRequestParser($request, $logger);","handlingStrategy":"validation","validationCode":"$body = $request->getBody();\nif (!stream_get_meta_data($body)['seekable']) {\n    $buf = fopen('php://temp', 'r+b');\n    stream_copy_to_stream($body, $buf);\n    rewind($buf);\n    $request->setBody($buf);\n}","typeGuard":"function isSeekableStream($stream): bool {\n    return is_resource($stream) && (stream_get_meta_data($stream)['seekable'] ?? false);\n}","tryCatchPattern":null,"preventionTips":["Always hand Sabre a seekable body resource (php://temp) in custom servers/front controllers","Check stream_get_meta_data($body)['seekable'] before constructing MultipartRequestParser","In tests, use fopen('php://memory', 'r+b') fixtures, not pipes"],"tags":["php","webdav","nextcloud","bulk-upload","stream","fseek"],"backgroundTag":"non-seekable-stream","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}