guzzle/guzzle · error · RuntimeException

A response must not contain both Content-Length and…

Error message

A response must not contain both Content-Length and Transfer-Encoding

What it means

Thrown by HeaderProcessor::validateResponseFraming() when a body-bearing response carries both a Content-Length and a Transfer-Encoding header. RFC 7230 forbids this combination to prevent framing ambiguity and request/response smuggling; the presence of both is a protocol violation.

Solutions

  1. Capture raw response headers (curl -v) to confirm both headers are present.
  2. Fix the proxy/gateway to strip one header per RFC 7230 (prefer Transfer-Encoding when chunked).
  3. If the server is out of your control, catch RuntimeException and decide whether to retry without strict framing.
  4. Report the violation to the server operator.

Example fix

// before - blind call to a non-conformant server
$resp = $client->get($url);

// after - tolerate the broken endpoint
try {
    $resp = $client->get($url);
} catch (\RuntimeException $e) {
    if (str_contains($e->getMessage(), 'both Content-Length and Transfer-Encoding')) {
        // fall back, log, or use a different endpoint
    }
    throw $e;
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
    $response = $client->get($url);
} catch (\RuntimeException $e) {
    if (str_contains($e->getMessage(), 'both Content-Length and Transfer-Encoding')) {
        // non-conformant server; fall back or report
    }
    throw $e;
}

Prevention

When it happens

Trigger: A server returns headers like 'Transfer-Encoding: chunked' together with 'Content-Length: 123' on a response that can have a body. validateResponseFraming() detects the overlap after parsing a valid Content-Length and finding a transfer-encoding key.

Common situations: A proxy adds Transfer-Encoding: chunked but does not strip the origin's Content-Length (or vice versa), a misconfigured reverse proxy, or a deliberately non-conformant test server.

Related errors


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

Appendix: source

Thrown at src/Handler/HeaderProcessor.php:188

        string $method,
        int $status,
        array $headers
    ): ?string {
        if (!self::responseCanHaveBody($method, $status)) {
            return null;
        }

        $normalizedKeys = Utils::normalizeHeaderKeys($headers);
        $contentLength = self::removeHeader('Content-Length', $headers);

        try {
            $length = self::parseContentLength($contentLength);
        } catch (\RuntimeException $e) {
            throw new \RuntimeException('Invalid Content-Length response header: '.$e->getMessage(), 0, $e);
        }

        if ($length !== null && isset($normalizedKeys['transfer-encoding'])) {
            throw new \RuntimeException('A response must not contain both Content-Length and Transfer-Encoding');
        }

        return $length;
    }

    /**
     * Removes every case-insensitive occurrence of a header and returns all
     * removed values in their original field order.
     *
     * @param array<string, string[]> $headers
     *
     * @return string[] Removed values across all header-name casings
     */
    public static function removeHeader(string $name, array &$headers): array
    {
        $values = [];

        foreach ($headers as $key => $headerValues) {

View on GitHub (pinned to d1cbca7697)