{"record":{"id":"2914202916a58396","repo":"guzzle/guzzle","slug":"the-stream-handler-cannot-guarantee-a-multiplexed","errorCode":null,"errorMessage":"The stream handler cannot guarantee a multiplexed protocol; required multiplexing needs a cURL handler.","messagePattern":"The stream handler cannot guarantee a multiplexed protocol; required multiplexing needs a cURL handler\\.","errorType":"exception","errorClass":"GuzzleHttp\\Exception\\RequestException","httpStatus":null,"severity":"error","filePath":"src/Handler/StreamHandler.php","lineNumber":174,"sourceCode":"\n        // Sleep if there is a delay specified.\n        if (isset($options['delay'])) {\n            \\usleep((int) ($options['delay'] * 1000));\n        }\n\n        $multiplex = $options['multiplex'] ?? null;\n\n        // Multiplexing::NONE is trivially satisfied: the stream handler sends\n        // one HTTP/1.x request per connection and never multiplexes.\n        if (null !== $multiplex && !\\in_array($multiplex, [Multiplexing::NONE, Multiplexing::EAGER, Multiplexing::WAIT, Multiplexing::REQUIRE_EAGER, Multiplexing::REQUIRE_WAIT], true)) {\n            throw new InvalidArgumentException(\\sprintf(\n                'The \"multiplex\" option must be null or a GuzzleHttp\\\\Multiplexing::* constant; received %s.',\n                \\get_debug_type($multiplex)\n            ));\n        }\n\n        if (\\in_array($multiplex, [Multiplexing::REQUIRE_EAGER, Multiplexing::REQUIRE_WAIT], true)) {\n            throw new RequestException('The stream handler cannot guarantee a multiplexed protocol; required multiplexing needs a cURL handler.', $request);\n        }\n\n        $protocolVersion = $request->getProtocolVersion();\n\n        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        if ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {\n            throw new RequestException(sprintf('HTTP/%s is not supported by the stream handler.', $protocolVersion), $request);\n        }\n\n        if (isset($options['on_stats']) && !\\is_callable($options['on_stats'])) {\n            throw new InvalidArgumentException('on_stats must be callable');","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/guzzle/guzzle/blob/d1cbca76970939a9c2ced55b1e25ea26f34fc773/src/Handler/StreamHandler.php#L156-L192","documentation":"Thrown by StreamHandler::__invoke when the 'multiplex' option is Multiplexing::REQUIRE_EAGER or REQUIRE_WAIT. PHP's HTTP stream wrapper speaks only HTTP/1.x (one request per connection), so it can never provide a multiplexed protocol; a hard requirement for multiplexing cannot be satisfied and the request is rejected up front. It is a RequestException (not InvalidArgumentException) because the option value is valid but the handler cannot honor it.","triggerScenarios":"Constructing a client on StreamHandler (or using Guzzle's default StreamHandler fallback when ext-curl is absent) and then passing 'multiplex' => Multiplexing::REQUIRE_EAGER / REQUIRE_WAIT on a request or as client config. The check is at src/Handler/StreamHandler.php:173.","commonSituations":"App config that mandates HTTP/2 multiplexing deployed on a host without ext-curl; shared client builder that forces REQUIRE_* multiplexing regardless of the underlying handler; switching handler at runtime from CurlHandler to StreamHandler.","solutions":["Install and enable ext-curl so Guzzle selects a cURL-based handler that supports multiplexed protocols.","Drop the REQUIRE_* constraint: use Multiplexing::EAGER/WAIT (advisory) or NONE, which the stream handler accepts.","Explicitly build the client with a CurlMultiHandler/CurlHandler when REQUIRE_* multiplexing is mandatory."],"exampleFix":"// before\n$client = new Client(['handler' => new StreamHandler()]);\n$client->get($u, ['multiplex' => Multiplexing::REQUIRE_EAGER]);\n// after\n$client = new Client(['handler' => new CurlMultiHandler()]);\n$client->get($u, ['multiplex' => Multiplexing::REQUIRE_EAGER]);","handlingStrategy":"fallback","validationCode":"use GuzzleHttp\\Multiplexing;\n$needsMultiplex = in_array($opts['multiplex'] ?? null, [Multiplexing::REQUIRE_EAGER, Multiplexing::REQUIRE_WAIT], true);\nif ($needsMultiplex && !extension_loaded('curl')) {\n    throw new \\RuntimeException('REQUIRE_* multiplexing needs ext-curl; cannot use StreamHandler');\n}","typeGuard":null,"tryCatchPattern":"try {\n    $client->send($req, ['multiplex' => Multiplexing::REQUIRE_EAGER]);\n} catch (\\GuzzleHttp\\Exception\\RequestException $e) {\n    if (str_contains($e->getMessage(), 'cannot guarantee a multiplexed protocol')) {\n        // fall back to advisory mode or a cURL handler\n    }\n}","preventionTips":["Ensure ext-curl is installed when multiplexing (HTTP/2) is required.","Use advisory Multiplexing::EAGER/WAIT rather than REQUIRE_* unless mandatory.","Select the handler based on required protocol capabilities."],"tags":["multiplex","stream-handler","http2","handler-selection"],"backgroundTag":null,"analyzedSha":"d1cbca76970939a9c2ced55b1e25ea26f34fc773","analyzedAt":"2026-08-06T00:37:27.795Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}