dotnet/aspnetcore · critical · Exception
SHA256 mismatch for {url}: expected {checksum}, got {sha256}
Error message
SHA256 mismatch for {url}: expected {checksum}, got {sha256} What it means
install-debs.py's download_file computes the SHA256 of the just-downloaded bytes and raises a plain Exception when it differs from the expected checksum supplied by the Packages index. This is integrity verification for individual .deb files pulled from the Debian/Ubuntu mirror. A mismatch means the bytes received are not the bytes the index recorded — possible tampering, a stale/republished package, or a transparent proxy serving wrong content.
Source
Thrown at eng/common/cross/install-debs.py:34
from collections import deque
from functools import cmp_to_key
async def download_file(session, url, dest_path, max_retries=3, retry_delay=2, timeout=60, checksum=None):
"""Asynchronous file download with retries."""
attempt = 0
while attempt < max_retries:
try:
async with session.get(url, timeout=aiohttp.ClientTimeout(total=timeout)) as response:
if response.status == 200:
with open(dest_path, "wb") as f:
content = await response.read()
# verify checksum if provided
if checksum:
sha256 = hashlib.sha256(content).hexdigest()
if sha256 != checksum:
raise Exception(f"SHA256 mismatch for {url}: expected {checksum}, got {sha256}")
f.write(content)
print(f"Downloaded {url} at {dest_path}")
return
else:
raise Exception(f"Failed to download {url}, Status Code: {response.status}")
except (asyncio.CancelledError, asyncio.TimeoutError, aiohttp.ClientError) as e:
print(f"Error downloading {url}: {type(e).__name__} - {e}. Retrying...")
attempt += 1
await asyncio.sleep(retry_delay)
raise Exception(f"Failed to download {url} after {max_retries} attempts.")
async def download_deb_files_parallel(mirror, packages, tmp_dir):
"""Download .deb files in parallel."""
os.makedirs(tmp_dir, exist_ok=True)
View on GitHub (pinned to 294cab2f9b)
Solutions
- Switch to an official, fully-synced mirror (e.g., http://deb.debian.org/debian or a known-good snapshot) and re-run.
- Clear any local HTTP cache/proxy between the host and the mirror, or disable the proxy for this download.
- Ensure --suite matches the mirror's actual published suite (mixing bookworm Packages.gz with sid .debs produces mismatches).
- If using a snapshot mirror, pin both the index and the debs to the same snapshot timestamp.
- Re-run after the mirror finishes syncing; transient mirror skew resolves on its own.
Example fix
# before python3 install-debs.py --arch amd64 --suite sid \ --mirror http://some-mirror/debian ... # fails: SHA256 mismatch # after python3 install-debs.py --arch amd64 --suite sid \ --mirror http://deb.debian.org/debian ...
Defensive patterns
Strategy: retry
Validate before calling
# Probe the URL and its expected checksum before invoking download_file
import hashlib, urllib.request
expected = info.get('SHA256')
if expected:
with urllib.request.urlopen(url) as r:
actual = hashlib.sha256(r.read()).hexdigest()
if actual != expected:
raise SystemExit(f'Pre-flight checksum mismatch for {url}; do not proceed') Try / catch
from tenacity import retry, stop_after_attempt, retry_if_exception_type
@retry(stop=stop_after_attempt(5),
retry=retry_if_exception_type(Exception),
reraise=True)
def safe_download(session, url, dest, checksum):
try:
await download_file(session, url, dest, checksum=checksum)
except Exception as e:
if 'SHA256 mismatch' in str(e):
print(f'Checksum skew for {url}, will retry from a fresh mirror')
raise # tenacity will retry
raise Prevention
- Pin to a single fully-synced mirror or a snapshot mirror so index and debs are consistent.
- Run --force-check-gpg in CI to anchor per-deb checksums to a signed Release.
- Clear corporate HTTP caches between rootfs builds.
- Log the URL and expected checksum on mismatch to identify the offending mirror.
When it happens
Trigger: download_file is called with a non-None checksum (which happens for .deb downloads in download_debs_files_parallel, where info.get('SHA256') from the parsed Packages index is passed). The recomputed sha256 differs from the recorded one. The exception propagates out of asyncio.gather and aborts the rootfs build.
Common situations: Mirror is mid-sync and serving a mix of old/new packages; a transparent HTTP cache (corporate proxy, container registry mirror) holds stale bytes; the suite/mirror combination points at an archive whose Packages.gz is from a different epoch than the .deb files; partial write corruption.
Related errors
- SHA256 mismatch for {path}: expected {packages_sha}, got {sh
- Failed to download {url}, Status Code: {response.status}
- Failed to download {url} after {max_retries} attempts.
- Could not find checksum for {path} in Release file.
- Signature verification failed: {result.stderr.decode('utf-8'
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/8b2fea2ff9f79cc5.
Report an issue: GitHub.