{"record":{"id":"b0270b0a48fd1da3","repo":"dotnet/efcore","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":"error","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/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/eng/common/cross/install-debs.py#L16-L52","documentation":"Raised by download_file when a caller-supplied checksum (the SHA256 from the Packages index, passed at line 61) does not match the SHA256 of the bytes actually received from the mirror. It signals a corrupted or substituted download. Note the exception is a bare Exception, so it is NOT one of the retryable types in the except tuple (CancelledError/TimeoutError/ClientError) and propagates immediately without retry.","triggerScenarios":"Calling download_file with checksum set (as download_deb_files_parallel does via info.get('SHA256')) and the body returned by {mirror}/{filename} hashes to a different value than the Packages index recorded.","commonSituations":"Mirror is mid-sync (inconsistent build published), CDN/cache serves a stale or different build, --mirror and --suite point to inconsistent sources, a corporate proxy or apt-cacher serves cached wrong bytes, or (rarely) a MITM altering bytes.","solutions":["Re-run against a different mirror (e.g. switch from a community mirror to the official one) since the most common cause is a mirror mid-publish.","Verify --mirror, --suite, and --arch are a consistent, valid combination.","Manually curl the failing {url}, compute sha256sum, and compare against the SHA256 field in the Packages index to confirm whether the mirror or the index is wrong.","Disable any transparent HTTP proxy (HTTP_PROXY/HTTPS_PROXY, apt-cacher) and retry.","If reproducible across mirrors, treat it as a potential integrity attack and investigate the source of the bytes."],"exampleFix":"// before\nif sha256 != checksum:\n    raise Exception(f\"SHA256 mismatch for {url}: expected {checksum}, got {sha256}\")  # propagates, NOT retried\n\n// after\nif sha256 != checksum:\n    raise aiohttp.ClientError(f\"SHA256 mismatch for {url}: expected {checksum}, got {sha256}\")  # now caught by the retry handler","handlingStrategy":"retry","validationCode":"# preflight: confirm the mirror serves the expected bytes for one sample package\nimport aiohttp, asyncio, hashlib\nasync def verify(mirror, filename, expected):\n    async with aiohttp.ClientSession() as s:\n        async with s.get(f\"{mirror}/{filename}\") as r:\n            data = await r.read()\n            return hashlib.sha256(data).hexdigest() == expected\n# asyncio.run(verify(args.mirror, sample_filename, sample_sha))","typeGuard":null,"tryCatchPattern":"try:\n    asyncio.run(download_package_index_parallel(...))\n    asyncio.run(install_packages(...))\nexcept Exception as e:\n    if \"SHA256 mismatch\" in str(e):\n        # integrity failure -> retry against a different trusted mirror, do NOT silently continue\n        raise SystemExit(f\"integrity failure, retry with another mirror: {e}\")\n    raise","preventionTips":["Pin --mirror to an official archive or a dated snapshot mirror so Release and Packages stay consistent.","Keep --force-check-gpg on so index integrity is verified before any .deb is trusted.","Disable transparent HTTP caches (apt-cacher, corporate proxies) that can serve stale .deb bytes."],"tags":["integrity","network","sha256","deb","mirror"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}