{"record":{"id":"f46d752671928926","repo":"dotnet/runtime","slug":"failed-to-download-url-after-max-retries-attem","errorCode":null,"errorMessage":"Failed to download {url} after {max_retries} attempts.","messagePattern":"Failed to download (.+?) after (.+?) attempts\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"eng/common/cross/install-debs.py","lineNumber":47,"sourceCode":"\n                        # verify checksum if provided\n                        if checksum:\n                            sha256 = hashlib.sha256(content).hexdigest()\n                            if sha256 != checksum:\n                                raise Exception(f\"SHA256 mismatch for {url}: expected {checksum}, got {sha256}\")\n\n                        f.write(content)\n                    print(f\"Downloaded {url} at {dest_path}\")\n                    return\n                else:\n                    raise Exception(f\"Failed to download {url}, Status Code: {response.status}\")\n        except (asyncio.CancelledError, asyncio.TimeoutError, aiohttp.ClientError) as e:\n            print(f\"Error downloading {url}: {type(e).__name__} - {e}. Retrying...\")\n\n        attempt += 1\n        await asyncio.sleep(retry_delay)\n\n    raise Exception(f\"Failed to download {url} after {max_retries} attempts.\")\n\nasync def download_deb_files_parallel(mirror, packages, tmp_dir):\n    \"\"\"Download .deb files in parallel.\"\"\"\n    os.makedirs(tmp_dir, exist_ok=True)\n\n    tasks = []\n    timeout = aiohttp.ClientTimeout(total=60)\n    async with aiohttp.ClientSession(timeout=timeout) as session:\n        for pkg, info in packages.items():\n            filename = info.get(\"Filename\")\n            if filename:\n                url = f\"{mirror}/{filename}\"\n                dest_path = os.path.join(tmp_dir, os.path.basename(filename))\n                tasks.append(asyncio.create_task(download_file(session, url, dest_path, checksum=info.get(\"SHA256\"))))\n\n        await asyncio.gather(*tasks)\n\nasync def download_package_index_parallel(mirror, arch, suites, check_sig, keyring):","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/eng/common/cross/install-debs.py#L29-L65","documentation":"download_file gives up after max_retries (default 3) attempts that all failed with timeouts, aiohttp ClientErrors, or non-200 responses. The exception bubbles out of asyncio.gather and aborts the whole rootfs build, because missing even one .deb would leave the rootfs unusable.","triggerScenarios":"All retry attempts in the download_file loop fail (network down, mirror unreachable, persistent 4xx/5xx, TLS errors, or repeated checksum failures). Raised at install-debs.py:47 after the loop exits.","commonSituations":"CI runner without outbound network to the mirror. Mirror is down or under maintenance. DNS resolution failure. Corporate firewall blocking the mirror. Transient outage lasting longer than retries*retry_delay.","solutions":["Check outbound connectivity to the mirror from the build host (curl/GET the URL).","Increase max_retries and retry_delay by editing the call, or retry the whole build later.","Switch --mirror to a reachable mirror (official Debian/Ubuntu, internal mirror, or a local apt-cacher).","If a proxy is required, configure HTTPS_PROXY/HTTP_PROXY for the build."],"exampleFix":"# before\npython3 install-debs.py --arch arm64 ... # network down, all 3 retries fail\n\n# after\nexport HTTPS_PROXY=http://corp-proxy:8080\npython3 install-debs.py --arch arm64 ... # or wait for mirror recovery and rerun","handlingStrategy":"retry","validationCode":"# Pre-flight connectivity check before running install-debs.py.\nimport socket, sys\nhost = 'deb.debian.org'\ntry:\n    socket.create_connection((host, 443), timeout=5).close()\nexcept OSError:\n    print(f'No route to {host}; configure proxy or pick reachable --mirror'); sys.exit(2)","typeGuard":null,"tryCatchPattern":"# Wrap the top-level invocation; download_file has exhausted its own retries.\nimport subprocess, sys\nfor attempt in range(3):\n    rc = subprocess.call([sys.executable, 'install-debs.py', *args])\n    if rc == 0:\n        break\n    if attempt == 2:\n        print('All rootfs build attempts failed; check mirror/proxy/network.')\n        sys.exit(rc)","preventionTips":["Ensure outbound HTTPS to the mirror is reachable from the build host.","Set HTTPS_PROXY in corporate environments.","Pick a stable, well-connected mirror for CI."],"tags":["dotnet-rootfs","debian","download","retry-exhausted","network","python"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}