guzzle/guzzle · error · \InvalidArgumentException

The "multiplex" request option cannot be Multiplexing::NONE…

Error message

The "multiplex" request option cannot be Multiplexing::NONE on a CurlMultiHandler that permits multiplexing and requires persistent transport sharing; set the "multiplex" client or CurlMultiHandler constructor option to Multiplexing::NONE, or use TransportSharing::PERSISTENT_PREFER.

What it means

Required persistent sharing forbids `CURLOPT_FRESH_CONNECT` because it kills connection reuse, but `Multiplexing::NONE` on a multiplexing handler may need to force a fresh connection to harden the sole-use guarantee on certain libcurl versions. To keep the guarantee version-independent, Guzzle rejects the combination outright.

Solutions

  1. Disable multiplexing globally via the `multiplex` client/handler option (`Multiplexing::NONE`), which makes NONE hold without forcing fresh connections.
  2. Switch required sharing to `TransportSharing::PERSISTENT_PREFER`.
  3. Drop the per-request `Multiplexing::NONE`.

Example fix

// before
new CurlMultiHandler(['transport_sharing' => TransportSharing::PERSISTENT_REQUIRE]);
$client->get($url, ['multiplex' => Multiplexing::NONE]);

// after
new CurlMultiHandler([
    'transport_sharing' => TransportSharing::PERSISTENT_REQUIRE,
    'multiplex' => Multiplexing::NONE,
]);
Defensive patterns

Strategy: validation

Validate before calling

$persistReq = ($hOpts['transport_sharing'] ?? null) === TransportSharing::PERSISTENT_REQUIRE;
$handlerPermitsMultiplex = ($hOpts['multiplex'] ?? null) !== Multiplexing::NONE;
if ($persistReq && $handlerPermitsMultiplex
    && ($reqOpts['multiplex'] ?? null) === Multiplexing::NONE
) {
    throw new \LogicException('PERSISTENT_REQUIRE sharing conflicts with per-request Multiplexing::NONE');
}

Prevention

When it happens

Trigger: Handler configured with `transport_sharing => TransportSharing::PERSISTENT_REQUIRE`, request with `'multiplex' => Multiplexing::NONE` over HTTP/1.x on a handler that permits multiplexing. Guarded at line 426.

Common situations: Requiring cross-handler connection reuse for performance while still marking specific sensitive requests as sole-use.

Related errors


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

Appendix: source

Thrown at src/Handler/CurlMultiHandler.php:432

            return;
        }

        if (!$this->ownsFactory) {
            throw new InvalidArgumentException('The "multiplex" request option can only be Multiplexing::NONE on a CurlMultiHandler with a custom "handle_factory" when the handler\'s own "multiplex" option is Multiplexing::NONE, because the guarantee is enforced against the native easy handle the factory controls.');
        }

        $version = $easy->request->getProtocolVersion();
        if ('1.0' !== $version && '1.1' !== $version) {
            throw new InvalidArgumentException('The "multiplex" request option can only be Multiplexing::NONE for an HTTP/1.x request on a CurlMultiHandler that permits multiplexing; set the "multiplex" client or CurlMultiHandler constructor option to Multiplexing::NONE to disable multiplexing for every transfer, or send the request with its "version" option set to "1.1".');
        }

        if (null !== $this->shareHandleState && TransportSharing::PERSISTENT_REQUIRE === $this->shareHandleState->mode) {
            // The matcher-window hardening below may force a fresh
            // connection, which required persistent sharing forbids because
            // it disables connection reuse (CurlFactory applies the same
            // rule to the raw option); rejected on every runtime so
            // acceptance stays version-independent.
            throw new InvalidArgumentException('The "multiplex" request option cannot be Multiplexing::NONE on a CurlMultiHandler that permits multiplexing and requires persistent transport sharing; set the "multiplex" client or CurlMultiHandler constructor option to Multiplexing::NONE, or use TransportSharing::PERSISTENT_PREFER.');
        }

        if (\defined('CURLOPT_HTTPAUTH')
            && isset($options['curl'])
            && \is_array($options['curl'])
            && \array_key_exists((int) \constant('CURLOPT_HTTPAUTH'), $options['curl'])
        ) {
            // Key presence alone conflicts: challenge-response retries are
            // libcurl-internal follows, which disarm CURLOPT_FRESH_CONNECT
            // (reuse_fresh && !this_is_a_follow), so the hardening below
            // cannot cover them.
            throw new InvalidArgumentException('The "multiplex" request option cannot be Multiplexing::NONE combined with the raw CURLOPT_HTTPAUTH cURL option on a CurlMultiHandler that permits multiplexing; remove the raw option, or set the "multiplex" client or CurlMultiHandler constructor option to Multiplexing::NONE.');
        }

        if (Psr7\Utils::caselessContains($easy->request->getHeaderLine('Expect'), '100-continue')) {
            // libcurl arms its Expect handling by a caseless substring scan
            // of the header value (Curl_compareheader), so any value
            // containing 100-continue can make a 417 response retry as an

View on GitHub (pinned to d1cbca7697)