dotnet/aspnetcore · critical · Exception
SHA256 mismatch for {path}: expected {packages_sha}, got {sh
Error message
SHA256 mismatch for {path}: expected {packages_sha}, got {sha256} What it means
When --force-check-gpg is set, fetch_and_decompress verifies each Packages.gz against the SHA256 recorded in the Release file before decompressing it. A mismatch raises a plain Exception. This catches a tampered or stale package index whose checksum does not match the signed Release — a stronger integrity guarantee than the per-deb check because it is anchored to a GPG-signed file.
Source
Thrown at eng/common/cross/install-debs.py:105
"""Fetch and decompress the Packages.gz file."""
path = f"{component}/binary-{arch}/Packages.gz"
url = f"{mirror}/dists/{suite}/{path}"
async with session.get(url) as response:
if response.status == 200:
compressed_data = await response.read()
decompressed_data = gzip.decompress(compressed_data).decode('utf-8')
print(f"Downloaded index: {url}")
if check_sig:
# Verify the package index against the sha256 recorded in the Release file
release_file_content = await fetch_release_file(session, mirror, suite, keyring)
packages_sha = parse_release_file(release_file_content, path)
sha256 = hashlib.sha256(compressed_data).hexdigest()
if sha256 != packages_sha:
raise Exception(f"SHA256 mismatch for {path}: expected {packages_sha}, got {sha256}")
print(f"Checksum verified for {path}")
return decompressed_data
else:
print(f"Skipped index: {url} (doesn't exist)")
return None
async def fetch_release_file(session, mirror, suite, keyring):
"""Fetch Release and Release.gpg files and verify the signature."""
release_url = f"{mirror}/dists/{suite}/Release"
release_gpg_url = f"{mirror}/dists/{suite}/Release.gpg"
with tempfile.NamedTemporaryFile() as release_file, tempfile.NamedTemporaryFile() as release_gpg_file:
await download_file(session, release_url, release_file.name)
await download_file(session, release_gpg_url, release_gpg_file.name)
print("Verifying signature of Release with Release.gpg.")View on GitHub (pinned to 294cab2f9b)
Solutions
- Use a mirror known to be fully synced (deb.debian.org, snapshot.debian.org pinned to a timestamp, or a local complete mirror).
- Wait for the mirror sync window to pass and re-run — Release/Packages skew is transient.
- If you trust the transport, you may drop --force-check-gpg to skip this check, but prefer fixing the mirror.
- Pin to a snapshot mirror (e.g., snapshot.debian.org/archive/debian/<timestamp>/) so Release and Packages are atomically consistent.
Example fix
# before — rolling mirror with Release/Packages skew python3 install-debs.py --force-check-gpg --keyring key.gpg \ --suite sid --mirror http://deb.debian.org/debian ... # SHA256 mismatch for main/binary-amd64/Packages.gz # after — pinned snapshot python3 install-debs.py --force-check-gpg --keyring key.gpg \ --suite sid --mirror http://snapshot.debian.org/archive/debian/20240101T000000Z/ ...
Defensive patterns
Strategy: fallback
Validate before calling
# Pre-validate Release/Packages consistency before extracting
async with session.get(release_url) as r:
release_text = await r.text()
packages_sha = parse_release_file(release_text, path)
# compare against the live Packages.gz hash; abort early if mismatch
if packages_sha is None:
print(f'No checksum recorded for {path} in Release; mirror layout mismatch') Try / catch
try:
content = await fetch_and_decompress(session, mirror, arch, suite, component, check_sig, keyring)
except Exception as e:
if 'SHA256 mismatch for' in str(e) and 'Packages' in str(e):
# Release/Packages skew — fall back to a snapshot mirror
snapshot_mirror = f'http://snapshot.debian.org/archive/debian/{pin}/'
content = await fetch_and_decompress(session, snapshot_mirror, arch, suite, component, check_sig, keyring)
raise Prevention
- Pin to a snapshot mirror so Release and Packages.gz are atomically consistent.
- Avoid rolling mirrors during their sync window.
- Run checksum verification in CI to catch mirror skew early.
- Keep --force-check-gpg on for production rootfs builds.
When it happens
Trigger: fetch_and_decompress fetches the Packages.gz for a suite/component, then if check_sig is True it fetches the Release file via gpgv-verified download, parses it for the sha256 of the relative path (e.g., main/binary-amd64/Packages.gz), and compares. A mismatch raises immediately.
Common situations: Mirror mid-sync (Release updated before Packages.gz or vice versa); partial mirror that ships Release but not the matching Packages; CDN serving a cached Release with fresh Packages; man-in-the-middle tampering.
Related errors
- SHA256 mismatch for {url}: expected {checksum}, got {sha256}
- Could not find checksum for {path} in Release file.
- Signature verification failed: {result.stderr.decode('utf-8'
- Failed to download {url}, Status Code: {response.status}
- Failed to download {url} after {max_retries} attempts.
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/53239fb65f1d09d6.
Report an issue: GitHub.