{"record":{"id":"437087a09524af21","repo":"dotnet/efcore","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/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/eng/common/cross/install-debs.py#L22-L58","documentation":"Raised by download_file when the HTTP response status is anything other than 200. The exception is thrown inside the per-attempt try block, so unlike network errors it is NOT caught by the (CancelledError, TimeoutError, ClientError) handler and propagates immediately without consuming the retry budget. It signals that the server answered but refused/failed the request (404, 403, 5xx, etc.).","triggerScenarios":"Calling download_file / download_deb_files_parallel / download_package_index_parallel where session.get(url) returns a non-200 status. Concretely: a missing Packages.gz under the given --suite/--arch (404), a forbidden mirror path (403), or a mirror/server error (500/502/503).","commonSituations":"Wrong --mirror base URL; --suite or --arch typo (e.g. 'sid' vs 'unstable', 'loong64' vs 'loongarch64'); component path not present on the mirror (e.g. requesting 'universe' on a Debian mirror); package Filename in the index pointing to a file the mirror no longer serves; mirror under maintenance returning 503.","solutions":["Open the exact {url} from the message in a browser or with `curl -I` to confirm the status code and the mirror's actual layout.","Re-check the --suite and --arch arguments against the mirror's dists/<suite>/ and binary-<arch> directory names.","Verify the --mirror URL is the correct base for the distro (Debian vs Debian-ports vs Ubuntu) and has no trailing/missing path segment.","If the mirror is returning 5xx, switch to another mirror or retry later."],"exampleFix":"# before\npython install-debs.py --mirror http://ftp.debian.org/debian --arch loong64 --suite sid ...\n# after (loong64 lives in debian-ports, not debian)\npython install-debs.py --mirror http://ftp.ports.debian.org/debian-ports --arch loong64 --suite sid ...","handlingStrategy":"try-catch","validationCode":"# Validate the URL is reachable and returns 200 before relying on download_file\nimport aiohttp, asyncio\n\nasync def check_url(url, timeout=30):\n    async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=timeout)) as s:\n        async with s.get(url) as r:\n            if r.status != 200:\n                raise RuntimeError(f\"{url} -> HTTP {r.status}; fix mirror/suite/arch before downloading\")\n            return True\n\nasyncio.run(check_url(f\"{mirror}/dists/{suite}/main/binary-{arch}/Packages.gz\"))","typeGuard":null,"tryCatchPattern":"# download_file raises bare Exception with the message; match on the prefix\ntry:\n    await download_file(session, url, dest_path, checksum=checksum)\nexcept Exception as e:\n    msg = str(e)\n    if msg.startswith(\"Failed to download\") and \"Status Code\" in msg:\n        # HTTP-level failure: do NOT blind-retry, fix the URL/suite/arch\n        raise SystemExit(f\"Mirror returned non-200 for {url}: {msg}\")\n    raise","preventionTips":["Resolve --mirror, --suite, --arch against the mirror's actual directory layout before running.","Use curl -I on the would-be Packages.gz and .deb URLs in CI smoke checks.","Prefer a canonical mirror over a random one; document the exact mirror per distro in your build config."],"tags":["network","http","download","mirror","configuration"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}