{"record":{"id":"1b4aa6077aa208c5","repo":"dotnet/aspnetcore","slug":"failed-to-download-url-status-code-response-s","errorCode":null,"errorMessage":"Failed to download {url}, Status Code: {response.status}","messagePattern":"Failed to download (.+?), Status Code: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"eng/common/cross/install-debs.py","lineNumber":40,"sourceCode":"    attempt = 0\n    while attempt < max_retries:\n        try:\n            async with session.get(url, timeout=aiohttp.ClientTimeout(total=timeout)) as response:\n                if response.status == 200:\n                    with open(dest_path, \"wb\") as f:\n                        content = await response.read()\n\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:","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/eng/common/cross/install-debs.py#L22-L58","documentation":"download_file raises a plain Exception when the HTTP response status is not 200, including the status code in the message. This fires before any retry accounting for the body — non-200 statuses are treated as download failures. The exception is caught by the except clause below (CancelledError/TimeoutError/ClientError) only for those specific types; a status-code Exception is re-raised and terminates the loop because it is not in the caught tuple, so it propagates immediately rather than retrying.","triggerScenarios":"A .deb URL or Release/Packages URL returns 404 (package removed from the suite), 403 (mirror access denied), or 5xx (mirror error). The Exception raised inside the try is NOT in the (CancelledError, TimeoutError, ClientError) tuple, so it escapes the retry loop and surfaces directly.","commonSituations":"Package was removed from the suite but the Packages index still references it; mirror requires authentication or blocks user-agents; CDN rate-limiting returns 429; wrong --suite producing 404s for the requested components.","solutions":["Confirm the --suite and --arch combination exists on the --mirror (open the dists/<suite>/ URL in a browser).","For 404 on a specific package, the suite may have moved the package — try a different suite or pin to a snapshot mirror.","For 403/429, reduce parallelism or use a different mirror that does not rate-limit.","Note: status-code errors do not retry by design; fix the URL/mirror rather than expecting the retry loop to help.","Temporarily remove --force-check-gpg to isolate whether the failure is the Release/Packages fetch vs the .deb fetch."],"exampleFix":"# before — wrong suite for the package\npython3 install-debs.py --suite stretch --mirror http://deb.debian.org/debian ...\n# 404 on libc6\n\n# after\npython3 install-debs.py --suite bookworm --mirror http://deb.debian.org/debian ...","handlingStrategy":"try-catch","validationCode":"# HEAD the URL before the bulk download to fail fast on 404/403\nimport aiohttp\nasync with aiohttp.ClientSession() as s:\n    async with s.head(url) as h:\n        if h.status != 200:\n            print(f'Pre-flight {h.status} for {url}; aborting before retry loop')\n            return False","typeGuard":null,"tryCatchPattern":"try:\n    await download_file(session, url, dest, checksum=checksum)\nexcept Exception as e:\n    msg = str(e)\n    if 'Status Code:' in msg:\n        code = int(msg.split('Status Code:')[1].strip())\n        if code in (404, 410):\n            print(f'Package permanently gone: {url}')\n            raise  # not retryable\n        # other codes might warrant a mirror switch\n    raise","preventionTips":["Validate --suite/--arch exist on the mirror before the bulk download.","Note that status-code errors bypass the retry loop by design; fix the URL.","Use HEAD requests to pre-flight package availability.","Log the failing URL and status to distinguish transient from permanent failures."],"tags":["python","debian","network","http","install-debs","rootfs"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}