dotnet/yarp · error · Exception
Failed to download {url}, Status Code: {response.status}
Error message
Failed to download {url}, Status Code: {response.status} What it means
This exception is raised inside download_file when the HTTP response status code is anything other than 200. It fires for 404 (the package path does not exist on this mirror), 403 (access denied), 5xx (server error), or redirect issues. Critically, this raises a generic Exception that is NOT caught by the except clause on line 41 (which only catches asyncio.CancelledError, asyncio.TimeoutError, and aiohttp.ClientError), so it propagates immediately without retry -- unlike network-level errors which retry up to max_retries times.
Source
Thrown at eng/common/cross/install-debs.py:40
attempt = 0
while attempt < max_retries:
try:
async with session.get(url, timeout=aiohttp.ClientTimeout(total=timeout)) as response:
if response.status == 200:
with open(dest_path, "wb") as f:
content = await response.read()
# 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:View on GitHub (pinned to bd11867bee)
Solutions
- Verify the exact URL by printing it and fetching it with curl -I to see the status code and confirm the path exists.
- Check that --mirror, --suite, and --arch are mutually compatible (e.g. amd64 uses debian.org, loongarch64 uses debian-ports).
- Make the non-200 case retriable by raising an aiohttp.ClientResponseError (a subclass of aiohttp.ClientError) instead of a bare Exception, so it is caught by the existing except clause and retried.
- If the package was removed from the pool, re-fetch the package index to get updated Filename references.
- Try a different mirror that has the requested suite/architecture.
Example fix
# before -- generic Exception is NOT caught by the except clause, so it never retries
else:
raise Exception(f"Failed to download {url}, Status Code: {response.status}")
# after -- raise aiohttp.ClientResponseError so the except (aiohttp.ClientError) clause catches and retries it
else:
raise aiohttp.ClientResponseError(
response.request_info,
response.history,
status=response.status,
message=f"Failed to download {url}, Status Code: {response.status}") Defensive patterns
Strategy: retry
Validate before calling
# Pre-check: verify the URL returns 200 before relying on it in the batch download loop.
import subprocess
result = subprocess.run(['curl', '-sI', url], capture_output=True)
status_line = result.stdout.decode().split('\n')[0]
if '200' not in status_line:
print(f"WARNING: {url} returns {status_line}. Check mirror/suite/arch combination.") Try / catch
# Fix the retry bug: catch the non-200 case so it retries like other download errors.
try:
await download_file(session, url, dest_path, checksum=checksum)
except aiohttp.ClientResponseError as e:
if e.status == 404:
print(f"Package not found at {url} -- check the Packages index.")
raise
else:
print(f"Transient HTTP error {e.status}, will be retried by download_file.")
raise Prevention
- Verify the mirror URL, suite, and architecture combination is valid before starting the batch download.
- Use curl -I to spot-check a few package URLs from the index before downloading all.
- Apply the code fix: change the bare Exception on non-200 to aiohttp.ClientResponseError so it is caught and retried.
- Use a reliable mirror that is known to have the requested suite/arch.
- Handle 404 specially -- it usually means the Packages index is stale and references a removed package.
When it happens
Trigger: session.get(url) returns a response with status != 200 inside download_file (lines 25-40). Common triggers: the mirror URL or package Filename path is wrong (404); the mirror requires authentication or blocks the user agent (403); the mirror is temporarily down (500/502/503); the suite/architecture combination does not exist on this mirror; the Packages index references a Filename that has been removed from the pool.
Common situations: Wrong --mirror URL or wrong --suite/--arch combination pointing to a non-existent repository path; using a Debian ports mirror for a mainstream arch or vice versa; the Packages index is stale and references a .deb that has been garbage-collected from the pool (404); mirror rate-limiting or geographic blocking (403); the mirror is undergoing maintenance (503). Note: because this path does not retry, a transient 503 will abort immediately rather than recovering.
Related errors
- SHA256 mismatch for {url}: expected {checksum}, got {sha256}
- Failed to download {url} after {max_retries} attempts.
- SHA256 mismatch for {path}: expected {packages_sha}, got {sh
- Could not find checksum for {path} in Release file.
- Signature verification failed: {result.stderr.decode('utf-8'
AI-assisted analysis of dotnet/yarp@bd11867bee (2026-08-13).
Data as JSON: /api/errors/f584ec4637474155.
Report an issue: GitHub.