{"record":{"id":"9ac76192b0749b6f","repo":"dotnet/yarp","slug":"sha256-mismatch-for-url-expected-checksum-go","errorCode":null,"errorMessage":"SHA256 mismatch for {url}: expected {checksum}, got {sha256}","messagePattern":"SHA256 mismatch for (.+?): expected (.+?), got (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"critical","filePath":"eng/common/cross/install-debs.py","lineNumber":34,"sourceCode":"\nfrom collections import deque\nfrom functools import cmp_to_key\n\nasync def download_file(session, url, dest_path, max_retries=3, retry_delay=2, timeout=60, checksum=None):\n    \"\"\"Asynchronous file download with retries.\"\"\"\n    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","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/dotnet/yarp/blob/bd11867bee7df522e7fd3effb08a9c85fd616908/eng/common/cross/install-debs.py#L16-L52","documentation":"This exception is raised inside download_file after a .deb file is fully downloaded but its computed SHA-256 hash does not match the checksum recorded in the Packages index. The checksum is passed from the package metadata (info.get('SHA256') at line 61). A mismatch means the downloaded bytes differ from what the repository index promises -- indicating a corrupted download, a mirror out of sync with its own index, a man-in-the-middle altering content, or a CDN cache serving a stale/wrong artifact.","triggerScenarios":"download_file is called (line 61) with a checksum extracted from the parsed Packages index. After response.read() returns the full content, hashlib.sha256(content).hexdigest() is compared against that checksum. The exception fires when they differ. This occurs when the mirror's package pool has been updated but the Packages.gz index is stale (or vice versa), when a CDN edge node serves a mismatched file, or when network corruption alters bytes in transit (rare with TCP but possible with proxy tampering).","commonSituations":"Mirror index and package pool are out of sync after a partial mirror update; a CDN or caching proxy serves a different version of the .deb than the index references; running against a Debian ports mirror (e.g. for loongarch64, riscv64) that lags behind; a corporate proxy that strips or rewrites content; disk corruption on the mirror; the mirror rotated packages between index fetch and deb download (race condition during active suite migration).","solutions":["Retry the download -- mirror sync races are often transient; the index and pool realign within minutes.","Switch to a different mirror that is fully synced (e.g. use a primary Debian/Ubuntu mirror instead of a secondary).","Check if the suite is in the middle of a release migration (e.g. testing to stable transition) and pin to a specific snapshot using snapshot.debian.org or archive.ubuntu.com timestamps.","If behind a corporate proxy, bypass it or verify it is not modifying content.","Re-fetch the package index immediately before downloading .deb files to minimise the window for mirror drift.","Verify the mirror URL in the --mirror argument is correct and points to a complete, up-to-date repository."],"exampleFix":"# before -- checksum mismatch aborts immediately\nif sha256 != checksum:\n    raise Exception(f\"SHA256 mismatch for {url}: expected {checksum}, got {sha256}\")\n\n# after -- log and retry a few times before failing, since mirror sync races are transient\nif sha256 != checksum:\n    print(f\"SHA256 mismatch for {url}: expected {checksum}, got {sha256}. Retrying ({attempt+1}/{max_retries})...\")\n    attempt += 1\n    await asyncio.sleep(retry_delay)\n    continue","handlingStrategy":"retry","validationCode":"# No code-level pre-check can prevent a checksum mismatch -- it is detected after download.\n# Best pre-check: verify the mirror is reachable.\nimport subprocess\nresult = subprocess.run(['curl', '-sI', f'{mirror}/dists/'], capture_output=True)\nif '200' not in result.stdout.decode():\n    print(f\"WARNING: Mirror {mirror} may not be fully accessible.\")","typeGuard":null,"tryCatchPattern":"# Wrap download_file calls to handle checksum mismatches with a fallback mirror\ntry:\n    await download_file(session, url, dest_path, checksum=checksum)\nexcept Exception as e:\n    if 'SHA256 mismatch' in str(e) and fallback_mirror:\n        fallback_url = url.replace(mirror, fallback_mirror)\n        print(f\"Checksum mismatch on primary mirror, trying fallback: {fallback_url}\")\n        await download_file(session, fallback_url, dest_path, checksum=checksum)\n    else:\n        raise","preventionTips":["Use fully-synced primary mirrors (deb.debian.org, archive.ubuntu.com) rather than secondary mirrors that may lag.","Pass --force-check-gpg to verify the Packages index against the signed Release file, so a tampered index is caught before download.","Use snapshot.debian.org or timestamped Ubuntu mirrors to guarantee index and package pool are from the same point in time.","Retry on checksum mismatch -- mirror sync races are usually transient.","If behind a corporate proxy, verify it is not modifying download content."],"tags":["python","debian","sha256","checksum","download","apt","mirror","security"],"backgroundTag":null,"analyzedSha":"bd11867bee7df522e7fd3effb08a9c85fd616908","analyzedAt":"2026-08-13T21:29:49.359Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}