{"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":"GuzzleHttp\\Exception\\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/9b200fc5805036b331d6031199880dadecae0275/src/Handler/CurlFactory.php#L238-L274","documentation":"Thrown during CurlFactory::create() when the request targets HTTP/3 (protocol version '3' or '3.0') but CurlVersion::supportsHttp3() returns false. HTTP/3 support requires libcurl 7.88.0+ built with the CURL_VERSION_HTTP3 feature bit and the CURL_HTTP_VERSION_3 / CURL_HTTP_VERSION_3ONLY PHP constants. The guard fails fast rather than silently downgrading to HTTP/2 or HTTP/1.1.","triggerScenarios":"Calling the handler with a request whose protocol version is '3' or '3.0' (e.g. $request->withProtocolVersion('3.0')) on a host whose libcurl lacks the CURL_VERSION_HTTP3 feature. Also reached if CURLOPT_HTTP_VERSION is set to CURL_HTTP_VERSION_3 via curl options while the version string is '3'.","commonSituations":"Default Debian/Ubuntu/RHEL PHP packages ship libcurl without HTTP/3 (no QUIC/ngtcp2). Alpine musl builds and most Docker PHP base images also lack it. A developer enables HTTP/3 after reading docs but tests on a CI runner or local machine that was never rebuilt with --with-openssl-quic or --with-ngtcp2/nghttp3.","solutions":["Install or rebuild libcurl with HTTP/3 support (e.g. apt install curl with quiche/ngtcp2, or build from source with --with-openssl-quic), then rebuild the PHP cURL extension against it.","Verify support at runtime: check that CurlVersion::supportsHttp3() (or curl_version()['features'] & CURL_VERSION_HTTP3) is non-zero before sending HTTP/3 requests.","If HTTP/3 is optional, fall back to HTTP/2 ('2.0') or HTTP/1.1 when the feature bit is absent.","Use a Docker image that bundles HTTP/3-capable libcurl (e.g. a custom image built on a distro with a QUIC-enabled curl)."],"exampleFix":"// before\n$response = $client->send($request->withProtocolVersion('3.0'));\n\n// after\nif (GuzzleHttp\\Handler\\CurlVersion::supportsHttp3()) {\n    $request = $request->withProtocolVersion('3.0');\n} else {\n    $request = $request->withProtocolVersion('2.0');\n}\n$response = $client->send($request);","handlingStrategy":"validation","validationCode":"use GuzzleHttp\\Handler\\CurlVersion;\nif (!CurlVersion::supportsHttp3()) {\n    // do not request version '3.0'; fall back to HTTP/2 or 1.1\n    $version = CurlVersion::supportsHttp2() ? '2.0' : '1.1';\n} else {\n    $version = '3.0';\n}\n$request = $request->withProtocolVersion($version);","typeGuard":"// HTTP/3 is a runtime capability, not a type; check the feature bit.\nfunction supportsHttp3(): bool {\n    return \\defined('CURL_VERSION_HTTP3')\n        && \\defined('CURL_HTTP_VERSION_3')\n        && \\defined('CURL_HTTP_VERSION_3ONLY')\n        && (curl_version()['features'] & \\CURL_VERSION_HTTP3) !== 0;\n}","tryCatchPattern":null,"preventionTips":["Check CurlVersion::supportsHttp3() before pinning protocol version '3.0'.","Document the libcurl build requirement (HTTP/3/QUIC) in deployment notes.","Use feature-detection, not version-string sniffing, for HTTP/3 support."],"tags":["http3","curl","protocol-version","environment"],"analyzedSha":"9b200fc5805036b331d6031199880dadecae0275","analyzedAt":"2026-08-04T21:24:26.648Z","schemaVersion":2}