guzzle/guzzle · error · GuzzleHttp\Exception\RequestException

The request body position is outside the stream size

Error message

The request body position is outside the stream size

What it means

Thrown by RequestFraming::bodySize() as a RequestException when a non-seekable body stream's tell() reports a position that is negative or greater than the stream's total size. The available byte count is computed as size - position; an out-of-range position makes that meaningless, so the handler rejects it before dispatch.

Solutions

  1. Use a seekable stream (e.g. GuzzleHttp\Psr7\Utils::streamFor($string)) so position is handled by rewind.
  2. Fix the custom stream's tell() and getSize() to return consistent, monotonic values.
  3. Wrap the body in a buffered stream and reset its position to 0 before assigning.
  4. If the source is php://input or a pipe, read it fully into a seekable buffer first.

Example fix

// before
$request = new Request('POST', '/u', [], $brokenNonSeekableStream); // tell() > size

// after
$buffer = \GuzzleHttp\Psr7\Utils::streamFor((string) $brokenNonSeekableStream);
$request = new Request('POST', '/u', [], $buffer);
Defensive patterns

Strategy: validation

Validate before calling

$body = $request->getBody();
if (!$body->isSeekable()) {
    $size = $body->getSize();
    try {
        $pos = $body->tell();
    } catch (\RuntimeException $e) {
        $pos = null;
    }
    if ($pos !== null && ($pos < 0 || $pos > $size)) {
        throw new \InvalidArgumentException('Body position is outside the stream size');
    }
}

Type guard

function bodyPositionIsConsistent(\Psr\Http\Message\StreamInterface $s): bool {
    if ($s->isSeekable()) {
        return true;
    }
    try {
        $pos = $s->tell();
    } catch (\RuntimeException $e) {
        return true;
    }
    return $pos >= 0 && $pos <= $s->getSize();
}

Prevention

When it happens

Trigger: A request body that is a non-seekable stream whose current position is inconsistent with its reported size (position < 0 or position > size). bodySize() reads tell() only for non-seekable streams and validates the range.

Common situations: A custom StreamInterface that returns inconsistent tell()/getSize(), a pipe/socket stream whose position accounting is broken, or a stream that was partially consumed and rewound incorrectly. Bugs in a decorated stream wrapper.

Related errors


AI-assisted analysis of guzzle/guzzle@d1cbca7697 (2026-08-06). Data as JSON: /api/errors/1cebd87d8b27b88d. Report an issue: GitHub.

Appendix: source

Thrown at src/Handler/RequestFraming.php:162

                $request,
                $e,
                'Timed out while determining the request body size',
                'Failed to determine the request body size'
            );
        }

        if ($seekable) {
            return $size;
        }

        try {
            $position = $body->tell();
        } catch (\RuntimeException $e) {
            return null;
        }

        if ($position < 0 || $position > $size) {
            throw new RequestException('The request body position is outside the stream size', $request);
        }

        return $size - $position;
    }

    /**
     * Materializes the body, stopping at the selected Content-Length when
     * present.
     *
     * @throws RequestException when the body cannot be fully rewound or read
     */
    public function materialize(): string
    {
        $body = $this->request->getBody();

        if ($this->contentLength === null) {
            try {
                return (string) $body;

View on GitHub (pinned to d1cbca7697)