{"record":{"id":"35bd24fb04758d28","repo":"composer/composer","slug":"failed-getting-info-from-curl-handle-i-url","errorCode":null,"errorMessage":"Failed getting info from curl handle {$i} ({url})","messagePattern":"Failed getting info from curl handle (.+?) \\((.+?)\\)","errorType":"exception","errorClass":"\\RuntimeException","httpStatus":null,"severity":"error","filePath":"src/Composer/Util/Http/CurlDownloader.php","lineNumber":361,"sourceCode":"\n        $active = true;\n        $this->checkCurlResult(curl_multi_exec($this->multiHandle, $active));\n        if (-1 === curl_multi_select($this->multiHandle, $this->selectTimeout)) {\n            // sleep in case select returns -1 as it can happen on old php versions or some platforms where curl does not manage to do the select\n            usleep(150);\n        }\n\n        while ($progress = curl_multi_info_read($this->multiHandle)) {\n            $curlHandle = $progress['handle'];\n            $result = $progress['result'];\n            $i = (int) $curlHandle;\n            if (!isset($this->jobs[$i])) {\n                continue;\n            }\n\n            $progress = curl_getinfo($curlHandle);\n            if (false === $progress) {\n                throw new \\RuntimeException('Failed getting info from curl handle '.$i.' ('.Url::sanitize($this->jobs[$i]['url']).')');\n            }\n            $job = $this->jobs[$i];\n            unset($this->jobs[$i]);\n            $error = curl_error($curlHandle);\n            $errno = curl_errno($curlHandle);\n            curl_multi_remove_handle($this->multiHandle, $curlHandle);\n            if (\\PHP_VERSION_ID < 80000) {\n                curl_close($curlHandle);\n            }\n\n            $headers = null;\n            $statusCode = null;\n            $response = null;\n            try {\n                // TODO progress\n                if (CURLE_OK !== $errno || $error || $result !== CURLE_OK) {\n                    $errno = $errno ?: $result;\n                    if (!$error && function_exists('curl_strerror')) {","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/composer/composer/blob/c435d285c9120efdca35696769c72ea9fdcc0466/src/Composer/Util/Http/CurlDownloader.php#L343-L379","documentation":"During CurlDownloader::tick(), after curl_multi_info_read reports a finished job, `curl_getinfo($curlHandle)` returns false, meaning the handle is no longer queryable. Composer throws because it cannot recover the HTTP status/timing info needed to build the response.","triggerScenarios":"CurlDownloader::tick() processes a completed handle (src/Composer/Util/Http/CurlDownloader.php:359-361); if the underlying handle was closed/invalidated between dispatch and info-read (rare internal state issue, libcurl/PHP-curl ABI mismatch, or a curl extension bug), curl_getinfo returns false.","commonSituations":"Bugs in libcurl or the PHP curl extension on certain versions; handle removed concurrently; very rare — usually signals a corrupt curl state, often after a curl extension crash or build mismatch.","solutions":["Upgrade the PHP curl extension and libcurl (`apt-get install --only-upgrade php-curl libcurl4`).","Run `composer self-update --2` to get the latest downloader fixes.","If reproducible, rule out an HTTP/2 stream bug by forcing HTTP/1.1 (avoid HTTP2-capable libcurl or set COMPOSER_IPRESOLVE).","Report upstream with the output of `php -i | grep -i cURL` if it persists."],"exampleFix":"// before\nRUN apt-get install -y php8.1-curl=8.1.0  # old libcurl\n\n// after\nRUN apt-get install -y --only-upgrade php8.1-curl libcurl4","handlingStrategy":"retry","validationCode":"// Sanity-check curl health before bulk downloads\n$h = curl_init('http://127.0.0.1');\n$info = $h !== false ? @curl_getinfo($h) : false;\nif ($info === false) {\n    throw new \\RuntimeException('curl extension is broken; upgrade libcurl/php-curl.');\n}","typeGuard":null,"tryCatchPattern":"try {\n    $downloader->tick();\n} catch (\\RuntimeException $e) {\n    if (str_starts_with($e->getMessage(), 'Failed getting info from curl handle')) {\n        // discard this downloader, build a fresh CurlDownloader, and retry the jobs\n    }\n    throw $e;\n}","preventionTips":["Keep libcurl and php-curl at current stable versions.","Avoid mixing PHP builds with a mismatched libcurl ABI.","Use `composer self-update` to get the latest downloader fixes."],"tags":["curl","multi","libcurl","internal","version"],"backgroundTag":null,"analyzedSha":"c435d285c9120efdca35696769c72ea9fdcc0466","analyzedAt":"2026-08-07T18:58:23.525Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}