dotnet/aspnetcore · error · Exception
Failed to download after attempts.
Error message
Failed to download {url} after {max_retries} attempts. What it means
Raised by download_file after the while loop exhausts max_retries (default 3) attempts. Each attempt can fail either via a non-200 status (which raises immediately as error 346) or via a network-level exception (asyncio.CancelledError, asyncio.TimeoutError, aiohttp.ClientError) that is caught and retried. This terminal error means every retry was defeated by a network exception.
Solutions
- From the same host, run curl -v <url> to confirm raw reachability and TLS.
- Increase the budget by passing a larger max_retries/retry_delay if you are invoking download_file directly (the CLI does not expose these), or just re-run the whole script a few times.
- Allow-list the mirror hostname in CI firewall / proxy and ensure DNS resolves.
- If on a constrained network, pre-stage the .deb files and skip the download step.
Example fix
# before python3 install-debs.py --mirror http://ftp.debian.org/debian --suite trixie --arch amd64 --rootfsdir rootfs libc6 # 'Failed to download ... after 3 attempts.' # after: confirm reachability, then retry curl -I http://ftp.debian.org/debian/dists/trixie/Release python3 install-debs.py --mirror http://deb.debian.org/debian --suite trixie --arch amd64 --rootfsdir rootfs libc6
Defensive patterns
Strategy: retry
Validate before calling
# Pre-flight reachability check before the run:
python3 - <<'PY'
import socket, sys
host = 'ftp.debian.org'
try: socket.create_connection((host, 80), 5).close()
except OSError as e: print('no egress:', e); sys.exit(1)
PY Try / catch
# In a wrapper script, retry the whole install-debs.py invocation N times: for i in 1 2 3; do python3 install-debs.py "$@" && break || sleep 30; done
Prevention
- Allow-list the mirror host in CI egress firewall.
- Run from a network with stable DNS and no TLS interception.
- For air-gapped CI, pre-stage the .deb files and skip the download path.
When it happens
Trigger: All attempts to session.get(url) failed with TimeoutError or aiohttp.ClientError (DNS, connection reset, TLS handshake failure) within the configured 60s per-request timeout; or the URL host is unreachable for the run's duration.
Common situations: No egress to the mirror host (sandboxed CI without network allow-list); DNS misconfiguration; flaky link with packet loss exceeding the 3-retry budget; mirror under heavy load dropping connections; corporate TLS interception breaking the aiohttp session; clock skew causing TLS cert validation failure.
Related errors
- Failed to download , Status Code
- SHA256 mismatch for : expected , got
- SHA256 mismatch for : expected , got
- Could not find checksum for
- Could not find 'data.tar.*' in
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/6b10c30ff60cbd35.
Report an issue: GitHub.
Appendix: source
Thrown at eng/common/cross/install-debs.py:47
# verify checksum if provided
if checksum:
sha256 = hashlib.sha256(content).hexdigest()
if sha256 != checksum:
raise Exception(f"SHA256 mismatch for {url}: expected {checksum}, got {sha256}")
f.write(content)
print(f"Downloaded {url} at {dest_path}")
return
else:
raise Exception(f"Failed to download {url}, Status Code: {response.status}")
except (asyncio.CancelledError, asyncio.TimeoutError, aiohttp.ClientError) as e:
print(f"Error downloading {url}: {type(e).__name__} - {e}. Retrying...")
attempt += 1
await asyncio.sleep(retry_delay)
raise Exception(f"Failed to download {url} after {max_retries} attempts.")
async def download_deb_files_parallel(mirror, packages, tmp_dir):
"""Download .deb files in parallel."""
os.makedirs(tmp_dir, exist_ok=True)
tasks = []
timeout = aiohttp.ClientTimeout(total=60)
async with aiohttp.ClientSession(timeout=timeout) as session:
for pkg, info in packages.items():
filename = info.get("Filename")
if filename:
url = f"{mirror}/{filename}"
dest_path = os.path.join(tmp_dir, os.path.basename(filename))
tasks.append(asyncio.create_task(download_file(session, url, dest_path, checksum=info.get("SHA256"))))
await asyncio.gather(*tasks)
async def download_package_index_parallel(mirror, arch, suites, check_sig, keyring):View on GitHub (pinned to 3600ca084e)