{"record":{"id":"53239fb65f1d09d6","repo":"dotnet/aspnetcore","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":"error","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/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/eng/common/cross/install-debs.py#L87-L123","documentation":"Raised by fetch_and_decompress when --force-check-gpg is set and the downloaded Packages.gz bytes hash to a different SHA256 than the value recorded in the Release file for that path. It guards the package index against mirror tampering or partial-publish drift, separate from the per-.deb check at error 345.","triggerScenarios":"fetch_and_decompress computes hashlib.sha256(compressed_data) on the raw gzip bytes of Packages.gz and compares against packages_sha returned by parse_release_file(release_file_content, path). Any mismatch raises this Exception before the index is parsed.","commonSituations":"Mirror is mid-publish: Release file was updated but Packages.gz still serves the previous bytes (or vice versa); mirror snapshotted at an inconsistent point; transparent proxy cached an older Packages.gz against a newer Release; suite was renamed or pointed at a wrong components path; an attacker altered the index (rare; the gpg check at 349 would usually catch the Release tampering first).","solutions":["Switch --mirror to a known-consistent one (deb.debian.org or archive.ubuntu.com) and re-run.","Drop corporate/transparent HTTP proxies that may serve stale cached bytes for Packages.gz while passing Release through fresh.","Retry after a few minutes if the mirror is mid-publish; persistent mismatch indicates a real mirror bug worth reporting.","Do not pass --force-check-gpg to silence it; that disables the entire chain of checks (348, 349, 350)."],"exampleFix":"# before\npython3 install-debs.py --mirror http://local-mirror/debian --suite trixie --arch amd64 \\\n  --rootfsdir rootfs --force-check-gpg --keyring /usr/share/keyrings/debian-archive-keyring.gpg libc6\n# 'SHA256 mismatch for main/binary-amd64/Packages.gz: expected ..., got ...'\n\n# after (canonical mirror, no proxy)\nunset http_proxy https_proxy\npython3 install-debs.py --mirror http://deb.debian.org/debian --suite trixie --arch amd64 \\\n  --rootfsdir rootfs --force-check-gpg --keyring /usr/share/keyrings/debian-archive-keyring.gpg libc6","handlingStrategy":"validation","validationCode":"# Compare the Release-file SHA256 for Packages.gz against the actual file before the run:\nrel=$(curl -fsS \"$MIRROR/dists/$SUITE/Release\")\nexp=$(printf '%s' \"$rel\" | awk -v p=\"main/binary-$ARCH/Packages.gz\" '$1 ~ /^[0-9a-f]{64}$/ && $3==p {print $1}')\ngot=$(curl -fsS \"$MIRROR/dists/$SUITE/main/binary-$ARCH/Packages.gz\" | sha256sum | cut -d' ' -f1)\n[ \"$exp\" = \"$got\" ] || { echo 'index/release drift; switch mirror'; exit 1; }","typeGuard":null,"tryCatchPattern":"try:\n    asyncio.run(download_package_index_parallel(mirror, arch, suites, True, keyring))\nexcept Exception as e:\n    if 'SHA256 mismatch' in str(e) and 'Packages.gz' in str(e):\n        print('Release/Packages.gz drift from mirror; switch --mirror.')\n        raise","preventionTips":["Prefer canonical mirrors; avoid local caches that may serve inconsistent Release/Packages.gz.","Disable transparent HTTP proxies during the run.","Treat persistent mismatch as a mirror bug, not a script bug."],"tags":["python","network","checksum","debian","gpg","security","cross-build"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}