{"id":"1cebd87d8b27b88d","repo":"guzzle/guzzle","slug":"the-request-body-position-is-outside-the-stream-si","errorCode":null,"errorMessage":"The request body position is outside the stream size","messagePattern":"The request body position is outside the stream size","errorType":"exception","errorClass":"GuzzleHttp\\Exception\\RequestException","httpStatus":null,"severity":"error","filePath":"src/Handler/RequestFraming.php","lineNumber":162,"sourceCode":"                $request,\n                $e,\n                'Timed out while determining the request body size',\n                'Failed to determine the request body size'\n            );\n        }\n\n        if ($seekable) {\n            return $size;\n        }\n\n        try {\n            $position = $body->tell();\n        } catch (\\RuntimeException $e) {\n            return null;\n        }\n\n        if ($position < 0 || $position > $size) {\n            throw new RequestException('The request body position is outside the stream size', $request);\n        }\n\n        return $size - $position;\n    }\n\n    /**\n     * Materializes the body, stopping at the selected Content-Length when\n     * present.\n     *\n     * @throws RequestException when the body cannot be fully rewound or read\n     */\n    public function materialize(): string\n    {\n        $body = $this->request->getBody();\n\n        if ($this->contentLength === null) {\n            try {\n                return (string) $body;","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/guzzle/guzzle/blob/9b200fc5805036b331d6031199880dadecae0275/src/Handler/RequestFraming.php#L144-L180","documentation":"Thrown by RequestFraming::bodySize() for a non-seekable body whose reported stream position (from tell()) is negative or greater than its reported size (getSize()). The handler computes the sendable bytes as size minus position for non-seekable streams, so an out-of-range position makes that computation meaningless and is rejected as corrupt body metadata.","triggerScenarios":"Attaching a custom StreamInterface whose tell() returns a value greater than getSize(), or a negative position; a non-seekable wrapper that advances past its reported size without updating it; a bug in a third-party stream decorator that misreports position.","commonSituations":"Custom stream decorators (FnStream, caching streams) with broken tell()/getSize(); streams backed by resources whose fstat-based size is stale after the file was truncated; using a stream that was already read to EOF without rewinding.","solutions":["Switch to a seekable stream so the handler uses getSize() directly and never consults tell().","Rewind the body ($body->rewind()) before dispatch so position is 0 and within size.","Fix the custom StreamInterface so tell() always returns a value in [0, getSize()].","Use Psr7\\Utils::streamFor() over the raw resource so position/size stay consistent."],"exampleFix":"// before: broken decorator\nclass MyStream implements StreamInterface {\n    public function tell(): int { return 9999; }\n    public function getSize(): ?int { return 100; }\n}\n// after\npublic function tell(): int { return ftell($this->resource); }","handlingStrategy":"validation","validationCode":"// For non-seekable bodies, verify position is within size.\n$body = $request->getBody();\nif (!$body->isSeekable()) {\n    try {\n        $pos = $body->tell();\n        $size = $body->getSize();\n        if ($size !== null && ($pos < 0 || $pos > $size)) {\n            throw new \\LogicException('Body position out of range');\n        }\n    } catch (\\RuntimeException $e) { /* tell() unavailable: framing will treat as unknown */ }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer seekable streams so the handler uses getSize() without consulting tell().","Rewind bodies before dispatch so the position starts at 0.","Unit-test custom StreamInterface decorators: tell() must stay within [0, getSize()]."],"tags":["stream","request-framing","validation","psr-7"],"analyzedSha":"9b200fc5805036b331d6031199880dadecae0275","analyzedAt":"2026-08-04T21:24:26.648Z","schemaVersion":2}