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

  1. Switch to an official, fully-synced mirror (e.g., http://deb.debian.org/debian or a known-good snapshot) and re-run.
  2. Clear any local HTTP cache/proxy between the host and the mirror, or disable the proxy for this download.
  3. Ensure --suite matches the mirror's actual published suite (mixing bookworm Packages.gz with sid .debs produces mismatches).
  4. If using a snapshot mirror, pin both the index and the debs to the same snapshot timestamp.
  5. 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

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


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/8b2fea2ff9f79cc5. Report an issue: GitHub.