guzzle/guzzle · critical · \RuntimeException
Connection cap options require a cap-capable cURL multi hand
Error message
Connection cap options require a cap-capable cURL multi handler or the allow_url_fopen ini setting for stream fallback.
What it means
chooseHandler() throws RuntimeException when the user requested connection caps (max_host_connections and/or max_total_connections) but no cap-capable cURL multi handler exists (curl_multi_exec missing) AND allow_url_fopen is disabled. Caps need CurlMultiHandler; the stream fallback path only exists when allow_url_fopen is on.
Source
Thrown at src/Utils.php:104
$sharingMode = TransportSharing::HANDLER_PREFER;
}
$handler = self::createCurlHandler($sharingMode, $handlerOptions);
if ($sharingRequired && $handler === null) {
throw new \RuntimeException('Required transport sharing requires the PHP cURL extension, curl_exec() or curl_multi_exec(), and a supported libcurl version with SSL support.');
}
if (\ini_get('allow_url_fopen')) {
return self::addStreamHandler($handler, $sharingMode, self::connectionCapOptions($handlerOptions));
}
if ($handler !== null) {
return $handler;
}
if ($connectionCapsRequired) {
throw new \RuntimeException('Connection cap options require a cap-capable cURL multi handler or the allow_url_fopen ini setting for stream fallback.');
}
throw new \RuntimeException('GuzzleHttp requires a supported cURL version with SSL support, the allow_url_fopen ini setting, or a custom HTTP handler.');
}
private static function isTransportSharingRequired(string $sharingMode): bool
{
return \in_array($sharingMode, [TransportSharing::HANDLER_REQUIRE, TransportSharing::PERSISTENT_REQUIRE], true);
}
/**
* @param array{max_host_connections?: mixed, max_total_connections?: mixed} $handlerOptions
*/
private static function hasConnectionCapOptions(array $handlerOptions): bool
{
return self::connectionCapOptions($handlerOptions) !== [];
}
View on GitHub (pinned to 9b200fc580)
Solutions
- Ensure ext-curl with multi support is installed (curl_multi_exec must exist): php -r 'var_dump(function_exists("curl_multi_exec"));'.
- Enable allow_url_fopen=1 in php.ini as a stream fallback (note security trade-offs).
- Drop the connection-cap options if neither is feasible.
- Note: caps cannot be combined with TransportSharing::PERSISTENT_REQUIRE (rejected earlier with its own message).
Example fix
// before Utils::chooseHandler(['max_host_connections' => 6]); // RuntimeException: Connection cap options require a cap-capable cURL multi handler ... // after (option A: provide curl multi) // docker-php-ext-install curl // after (option B: allow stream fallback) // php.ini: allow_url_fopen = On // after (option C: drop caps) Utils::chooseHandler([]);
Defensive patterns
Strategy: validation
Validate before calling
// Validate cap feasibility before requesting caps:
$capCapable = function_exists('curl_multi_exec') || ini_get('allow_url_fopen');
$opts = $capCapable ? ['max_host_connections' => 6] : []; // drop caps if not feasible
Utils::chooseHandler($opts); Type guard
function connectionCapsFeasible(): bool
{
return function_exists('curl_multi_exec') || (bool) ini_get('allow_url_fopen');
} Try / catch
try {
$handler = Utils::chooseHandler(['max_host_connections' => 6]);
} catch (\RuntimeException $e) {
// Drop the caps and proceed without connection limits
$handler = Utils::chooseHandler([]);
} Prevention
- Ensure curl_multi_exec exists in images that need caps, or enable allow_url_fopen as fallback.
- Decide caps at deploy time from a capability probe, not hardcoded config.
- Remember caps are incompatible with TransportSharing::PERSISTENT_REQUIRE.
When it happens
Trigger: Setting max_host_connections / max_total_connections in handler options on a runtime without curl_multi_exec and with allow_url_fopen=0 in php.ini.
Common situations: Locking down allow_url_fopen for security while expecting connection caps without ensuring ext-curl (with multi) is present; minimal images that strip either curl or fopen.
Related errors
- Invalid CurlHandler constructor option "%s".
- Invalid CurlMultiHandler constructor option "%s".
- The "multiplex" CurlMultiHandler option only accepts Multipl
- options must be an array of cURL multi options
- Passing %s in the cURL multi handler "options" is not suppor
AI-assisted analysis of guzzle/guzzle@9b200fc580 (2026-08-04).
Data as JSON: /data/errors/ede3550598ea5b44.json.
Report an issue: GitHub.