{"record":{"id":"d8695bf0bdd9e69f","repo":"guzzle/guzzle","slug":"http-3-is-supported-by-the-curl-handler-however-t","errorCode":null,"errorMessage":"HTTP/3 is supported by the cURL handler, however the installed PHP cURL extension or libcurl does not support HTTP/3.","messagePattern":"HTTP/3 is supported by the cURL handler, however the installed PHP cURL extension or libcurl does not support HTTP/3\\.","errorType":"exception","errorClass":"RequestException","httpStatus":null,"severity":"error","filePath":"src/Handler/CurlFactory.php","lineNumber":256,"sourceCode":"        if ('' === $protocolVersion) {\n            throw new RequestException('HTTP protocol version must not be empty.', $request);\n        }\n\n        if (1 !== \\preg_match('/^\\d+(?:\\.\\d+)?$/D', $protocolVersion)) {\n            throw new RequestException('HTTP protocol version must be a valid HTTP version number.', $request);\n        }\n\n        CurlVersion::ensureSupported($request);\n\n        $multiplex = self::normalizeMultiplex($options);\n\n        if ('3' === $protocolVersion || '3.0' === $protocolVersion) {\n            if (!CurlVersion::supportsHttp3()) {\n                if (\\in_array($multiplex, [Multiplexing::REQUIRE_EAGER, Multiplexing::REQUIRE_WAIT], true)) {\n                    throw new RequestException('Required multiplexing for HTTP/3 needs libcurl 8.13.0 or newer built with HTTP/3 support.', $request);\n                }\n\n                throw new RequestException('HTTP/3 is supported by the cURL handler, however the installed PHP cURL extension or libcurl does not support HTTP/3.', $request);\n            }\n        } elseif ('2' === $protocolVersion || '2.0' === $protocolVersion) {\n            if (!CurlVersion::supportsHttp2()) {\n                if (\\in_array($multiplex, [Multiplexing::REQUIRE_EAGER, Multiplexing::REQUIRE_WAIT], true)) {\n                    throw new RequestException('Required multiplexing needs libcurl 8.14.0 or newer built with HTTP/2 support.', $request);\n                }\n\n                throw new RequestException('HTTP/2 is supported by the cURL handler, however libcurl 7.65.2 or newer built with HTTP/2 support is required.', $request);\n            }\n        } elseif ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {\n            throw new RequestException(sprintf('HTTP/%s is not supported by the cURL handler.', $protocolVersion), $request);\n        }\n\n        if (isset($options['curl']['body_as_string'])) {\n            $options['_body_as_string'] = $options['curl']['body_as_string'];\n            unset($options['curl']['body_as_string']);\n        }\n","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/guzzle/guzzle/blob/d1cbca76970939a9c2ced55b1e25ea26f34fc773/src/Handler/CurlFactory.php#L238-L274","documentation":"Thrown when a request pins HTTP/3 (protocol version '3' or '3.0') but the installed PHP cURL extension or libcurl cannot do HTTP/3 (no CURL_VERSION_HTTP3 feature bit, libcurl older than 7.88.0, or the CURL_HTTP_VERSION_3/3ONLY constants are absent). Guzzle pins HTTP/3 via CURL_HTTP_VERSION_3ONLY so it needs dependable support rather than an opportunistic upgrade, hence it fails the request with a RequestException. Only reached when multiplex is NOT set to REQUIRE_EAGER/REQUIRE_WAIT (that combination throws a different HTTP/3 message at line 253).","triggerScenarios":"A request built with ->withProtocolVersion('3') (or '3.0'), sent through CurlHandler/CurlMultiHandler, where curl_version()['features'] lacks the CURL_VERSION_HTTP3 bit or libcurl < 7.88.0. The 'multiplex' option must be absent, null, or a non-REQUIRE value.","commonSituations":"Default Debian/Ubuntu libcurl ships without an HTTP/3 backend (ngtcp2/quiche). Alpine's curl package historically lacks HTTP/3. CI images pinned to older curl. A dev who tested on a quiche-enabled build then deployed to a minimal container.","solutions":["Rebuild libcurl with an HTTP/3 backend (quiche, ngtcp2+nghttp3, or openssl-quic) and rebuild ext-curl against it; verify with (curl_version()['features'] & CURL_VERSION_HTTP3) !== 0.","Downgrade the request to HTTP/2 ('2') or HTTP/1.1 so ALPN negotiation handles it without HTTP/3.","Fall back to StreamHandler if HTTP/3 is optional and you only need the call to succeed."],"exampleFix":"// before\n$request = $request->withProtocolVersion('3');\n\n// after\n$request = $request->withProtocolVersion('2');","handlingStrategy":"validation","validationCode":"$v = function_exists('curl_version') ? curl_version() : false;\n$supportsHttp3 = is_array($v)\n    && defined('CURL_VERSION_HTTP3')\n    && defined('CURL_HTTP_VERSION_3')\n    && defined('CURL_HTTP_VERSION_3ONLY')\n    && version_compare($v['version'], '7.88.0', '>=')\n    && (((int) constant('CURL_VERSION_HTTP3')) & $v['features']) !== 0;\nif (!$supportsHttp3 && in_array($request->getProtocolVersion(), ['3', '3.0'], true)) {\n    $request = $request->withProtocolVersion('2');\n}","typeGuard":null,"tryCatchPattern":"try {\n    $response = $client->send($request);\n} catch (\\GuzzleHttp\\Exception\\RequestException $e) {\n    if (str_contains($e->getMessage(), 'does not support HTTP/3')) {\n        // retry with an HTTP/2 or HTTP/1.1 request\n    }\n    throw $e;\n}","preventionTips":["Gate HTTP/3 usage behind a curl_version() feature check at boot.","Document the deployment's required libcurl build (HTTP/3 backend) next to the client setup."],"tags":["http3","curl","version","runtime-capability"],"backgroundTag":null,"analyzedSha":"d1cbca76970939a9c2ced55b1e25ea26f34fc773","analyzedAt":"2026-08-06T00:37:27.795Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}