guzzle/guzzle · error · GuzzleHttp\Exception\ResponseTransferException
Failed while transferring the response body
Error message
Failed while transferring the response body
What it means
Thrown by StreamHandler::drain() when copying the response body fails with a generic exception that is neither a TimeoutException nor an OverflowException; if the underlying message is empty the default text 'Failed while transferring the response body' is used. It is wrapped as a ResponseTransferException carrying both request and response.
Source
Thrown at src/Handler/StreamHandler.php:710
// that number of bytes has been read. This can prevent infinitely
// reading from a stream when dealing with servers that do not
// honor Connection: Close headers.
$copied = Psr7\Utils::copyToStream($source, $target, $copyLimit);
} catch (ResponseException $e) {
throw $e;
} catch (TimeoutException $e) {
throw new ResponseTimeoutException(
'Timed out while transferring the response body',
$request,
$response,
$e
);
} catch (\OverflowException $e) {
throw new ResponseException($e->getMessage(), $request, $response, $e);
} catch (\Exception $e) {
// Any other response-body transfer failure surfaces as a
// ResponseTransferException carrying the response.
throw new ResponseTransferException(
$e->getMessage() !== '' ? $e->getMessage() : 'Failed while transferring the response body',
$request,
$response,
$e
);
}
$receivedLength = $encodedBody !== null ? $encodedBody->getBytesRead() : $copied;
if ($declaredLength !== null && $receivedLength < $declaredLength) {
throw new ResponseTransferException(
'Response body ended before the declared Content-Length was reached',
$request,
$response
);
}
try {
if ($sink->isSeekable()) {View on GitHub (pinned to 9b200fc580)
Solutions
- Catch ResponseTransferException and retry with backoff (transient resets often succeed).
- If using a 'sink' file, verify the destination is writable and has free disk space.
- Check the underlying exception (getPrevious()) for the real OS-level error and address it.
- For flaky endpoints, enable retry middleware or an idempotent retry policy.
Example fix
// before
$resp = $client->get($largeFileUrl); // fails mid-transfer
// after
try {
$resp = $client->get($largeFileUrl);
} catch (ResponseTransferException $e) {
// log $e->getPrevious() and retry with backoff
} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check the sink destination is writable before the transfer.
if (is_string($options['sink'] ?? null) && !is_writable(dirname($options['sink']))) {
throw new \RuntimeException('sink directory is not writable');
} Try / catch
try {
$response = $client->get($url);
} catch (\GuzzleHttp\Exception\ResponseTransferException $e) {
// inspect $e->getPrevious() for the OS-level cause; retry with backoff if transient
} Prevention
- Verify 'sink' destinations are writable and have free disk space.
- Use retry middleware with idempotent methods for flaky endpoints.
- Log getPrevious() to distinguish resets from local I/O failures.
When it happens
Trigger: The transport read fails partway through (broken pipe, connection reset, SSL read error) without matching a recognized timeout signature; a custom sink stream throws on write; the underlying resource is closed externally.
Common situations: Unstable networks dropping connections mid-download; intermediate proxies resetting the connection; disk-full or permission errors writing to a 'sink' file; resource exhaustion.
Related errors
- Timed out while transferring the response body
- Response body ended before the declared Content-Length was r
- Failed to rewind the response body
- Timed out while writing the response body
- Error creating resource
AI-assisted analysis of guzzle/guzzle@9b200fc580 (2026-08-04).
Data as JSON: /data/errors/71c467f405249553.json.
Report an issue: GitHub.