{"id":"ea4fdeb2c2fa6021","repo":"guzzle/guzzle","slug":"a-response-must-not-contain-both-content-length-an","errorCode":null,"errorMessage":"A response must not contain both Content-Length and Transfer-Encoding","messagePattern":"A response must not contain both Content-Length and Transfer-Encoding","errorType":"exception","errorClass":"\\RuntimeException","httpStatus":null,"severity":"error","filePath":"src/Handler/HeaderProcessor.php","lineNumber":188,"sourceCode":"        string $method,\n        int $status,\n        array $headers\n    ): ?string {\n        if (!self::responseCanHaveBody($method, $status)) {\n            return null;\n        }\n\n        $normalizedKeys = Utils::normalizeHeaderKeys($headers);\n        $contentLength = self::removeHeader('Content-Length', $headers);\n\n        try {\n            $length = self::parseContentLength($contentLength);\n        } catch (\\RuntimeException $e) {\n            throw new \\RuntimeException('Invalid Content-Length response header: '.$e->getMessage(), 0, $e);\n        }\n\n        if ($length !== null && isset($normalizedKeys['transfer-encoding'])) {\n            throw new \\RuntimeException('A response must not contain both Content-Length and Transfer-Encoding');\n        }\n\n        return $length;\n    }\n\n    /**\n     * Removes every case-insensitive occurrence of a header and returns all\n     * removed values in their original field order.\n     *\n     * @param array<string, string[]> $headers\n     *\n     * @return string[] Removed values across all header-name casings\n     */\n    public static function removeHeader(string $name, array &$headers): array\n    {\n        $values = [];\n\n        foreach ($headers as $key => $headerValues) {","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/guzzle/guzzle/blob/9b200fc5805036b331d6031199880dadecae0275/src/Handler/HeaderProcessor.php#L170-L206","documentation":"Thrown by HeaderProcessor::validateResponseFraming() when a response that can carry a body has both a Content-Length and a Transfer-Encoding header. RFC 7230 forbids the combination and it is a classic request/response-smuggling signal, so Guzzle rejects it outright. \\RuntimeException.","triggerScenarios":"The origin or a proxy chain sends both 'Content-Length' and 'Transfer-Encoding' on the same response (e.g. 'Transfer-Encoding: chunked' plus a stale Content-Length).","commonSituations":"Misconfigured reverse proxy/CDN that forwards both headers, an older intermediary, or a deliberate smuggling attempt.","solutions":["Inspect the response headers for the simultaneous CL + TE pair","Fix the intermediary so it strips one (chunked responses should not carry Content-Length)","try/catch the request to handle the framing conflict defensively"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    $response = $client->request('GET', $url);\n} catch (\\RuntimeException $e) {\n    if (str_contains($e->getMessage(), 'both Content-Length and Transfer-Encoding')) {\n        // framing conflict — fix the origin/proxy that emits both\n    }\n}","preventionTips":["Configure proxies to strip Content-Length when applying chunked encoding","Treat this error as a potential smuggling signal in production","Audit CDN/intermediary header handling during integration"],"tags":["response-smuggling","transfer-encoding","content-length","headers"],"analyzedSha":"9b200fc5805036b331d6031199880dadecae0275","analyzedAt":"2026-08-04T21:24:26.648Z","schemaVersion":2}