{"record":{"id":"d109f8cfda562305","repo":"dotnet/efcore","slug":"sha256-mismatch-for-path-expected-packages-sha","errorCode":null,"errorMessage":"SHA256 mismatch for {path}: expected {packages_sha}, got {sha256}","messagePattern":"SHA256 mismatch for (.+?): expected (.+?), got (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"critical","filePath":"eng/common/cross/install-debs.py","lineNumber":105,"sourceCode":"    \"\"\"Fetch and decompress the Packages.gz file.\"\"\"\n\n    path = f\"{component}/binary-{arch}/Packages.gz\"\n    url = f\"{mirror}/dists/{suite}/{path}\"\n\n    async with session.get(url) as response:\n        if response.status == 200:\n            compressed_data = await response.read()\n            decompressed_data = gzip.decompress(compressed_data).decode('utf-8')\n            print(f\"Downloaded index: {url}\")\n\n            if check_sig:\n                # Verify the package index against the sha256 recorded in the Release file\n                release_file_content = await fetch_release_file(session, mirror, suite, keyring)\n                packages_sha = parse_release_file(release_file_content, path)\n\n                sha256 = hashlib.sha256(compressed_data).hexdigest()\n                if sha256 != packages_sha:\n                    raise Exception(f\"SHA256 mismatch for {path}: expected {packages_sha}, got {sha256}\")\n                print(f\"Checksum verified for {path}\")\n\n            return decompressed_data\n        else:\n            print(f\"Skipped index: {url} (doesn't exist)\")\n            return None\n\nasync def fetch_release_file(session, mirror, suite, keyring):\n    \"\"\"Fetch Release and Release.gpg files and verify the signature.\"\"\"\n\n    release_url = f\"{mirror}/dists/{suite}/Release\"\n    release_gpg_url = f\"{mirror}/dists/{suite}/Release.gpg\"\n\n    with tempfile.NamedTemporaryFile() as release_file, tempfile.NamedTemporaryFile() as release_gpg_file:\n        await download_file(session, release_url, release_file.name)\n        await download_file(session, release_gpg_url, release_gpg_file.name)\n\n        print(\"Verifying signature of Release with Release.gpg.\")","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/eng/common/cross/install-debs.py#L87-L123","documentation":"Raised by fetch_and_decompress when --force-check-gpg is on: the SHA256 of the downloaded Packages.gz does not equal the SHA256 recorded for that path in the signed Release file. It means two files the mirror must serve consistently are out of agreement, i.e. a package-index integrity failure.","triggerScenarios":"check_sig is true; the bytes of {mirror}/dists/{suite}/{component}/binary-{arch}/Packages.gz hash to a value different from the SHA256 entry parse_release_file extracted from {mirror}/dists/{suite}/Release.","commonSituations":"Mirror mid-publish (Release updated but Packages.gz not yet propagated, or the reverse), a CDN layering violation serving mixed versions, a transparent proxy caching one file but not the other, or (rarely) a compromised mirror.","solutions":["Use a different official mirror, or a snapshot mirror pinned to a single instant (e.g. snapshot.debian.org) where Release and Packages.gz are guaranteed consistent.","Wait and re-run if the mirror appears to be mid-sync.","Manually curl both files, sha256sum them, and compare to the Release SHA256 line to identify which side is wrong.","Only as a last resort and if you accept the risk, drop --force-check-gpg (the script suggests --skipsigcheck in build-rootfs.sh)."],"exampleFix":"// before\n--mirror http://deb.debian.org/debian-ports --force-check-gpg --keyring ...\n\n// after\n# pin a single consistent instant of the archive\n--mirror http://snapshot.debian.org/archive/debian-ports/20260101T000000Z --force-check-gpg --keyring ...","handlingStrategy":"retry","validationCode":"# preflight: verify Release and Packages.gz agree on one suite before the full run\nimport urllib.request, gzip, hashlib\ndef check(mirror, suite, path):\n    rel = urllib.request.urlopen(f\"{mirror}/dists/{suite}/Release\").read().decode()\n    pkg = urllib.request.urlopen(f\"{mirror}/dists/{suite}/{path}\").read()\n    expected = next(l.split()[0] for l in rel.splitlines() if l.endswith(path) and len(l.split()[0])==64)\n    return hashlib.sha256(pkg).hexdigest() == expected\n# assert check(args.mirror, args.suite[0], 'main/binary-amd64/Packages.gz')","typeGuard":null,"tryCatchPattern":"try:\n    asyncio.run(download_package_index_parallel(mirror, arch, suites, True, keyring))\nexcept Exception as e:\n    if \"SHA256 mismatch for\" in str(e):\n        # Release/Packages disagreement -> switch to a snapshot mirror and retry\n        raise SystemExit(f\"index integrity failure, use a snapshot mirror: {e}\")\n    raise","preventionTips":["Use snapshot mirrors pinned to a single instant so Release and Packages.gz cannot disagree.","Avoid running during a mirror's publish window.","Do not disable --force-check-gpg just to bypass this; it hides real integrity problems."],"tags":["integrity","gpg","sha256","mirror","security"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}