dotnet/yarp · critical · Exception

SHA256 mismatch for {url}: expected {checksum}, got {sha256}

Error message

SHA256 mismatch for {url}: expected {checksum}, got {sha256}

What it means

This exception is raised inside download_file after a .deb file is fully downloaded but its computed SHA-256 hash does not match the checksum recorded in the Packages index. The checksum is passed from the package metadata (info.get('SHA256') at line 61). A mismatch means the downloaded bytes differ from what the repository index promises -- indicating a corrupted download, a mirror out of sync with its own index, a man-in-the-middle altering content, or a CDN cache serving a stale/wrong artifact.

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 bd11867bee)

Solutions

  1. Retry the download -- mirror sync races are often transient; the index and pool realign within minutes.
  2. Switch to a different mirror that is fully synced (e.g. use a primary Debian/Ubuntu mirror instead of a secondary).
  3. Check if the suite is in the middle of a release migration (e.g. testing to stable transition) and pin to a specific snapshot using snapshot.debian.org or archive.ubuntu.com timestamps.
  4. If behind a corporate proxy, bypass it or verify it is not modifying content.
  5. Re-fetch the package index immediately before downloading .deb files to minimise the window for mirror drift.
  6. Verify the mirror URL in the --mirror argument is correct and points to a complete, up-to-date repository.

Example fix

# before -- checksum mismatch aborts immediately
if sha256 != checksum:
    raise Exception(f"SHA256 mismatch for {url}: expected {checksum}, got {sha256}")

# after -- log and retry a few times before failing, since mirror sync races are transient
if sha256 != checksum:
    print(f"SHA256 mismatch for {url}: expected {checksum}, got {sha256}. Retrying ({attempt+1}/{max_retries})...")
    attempt += 1
    await asyncio.sleep(retry_delay)
    continue
Defensive patterns

Strategy: retry

Validate before calling

# No code-level pre-check can prevent a checksum mismatch -- it is detected after download.
# Best pre-check: verify the mirror is reachable.
import subprocess
result = subprocess.run(['curl', '-sI', f'{mirror}/dists/'], capture_output=True)
if '200' not in result.stdout.decode():
    print(f"WARNING: Mirror {mirror} may not be fully accessible.")

Try / catch

# Wrap download_file calls to handle checksum mismatches with a fallback mirror
try:
    await download_file(session, url, dest_path, checksum=checksum)
except Exception as e:
    if 'SHA256 mismatch' in str(e) and fallback_mirror:
        fallback_url = url.replace(mirror, fallback_mirror)
        print(f"Checksum mismatch on primary mirror, trying fallback: {fallback_url}")
        await download_file(session, fallback_url, dest_path, checksum=checksum)
    else:
        raise

Prevention

When it happens

Trigger: download_file is called (line 61) with a checksum extracted from the parsed Packages index. After response.read() returns the full content, hashlib.sha256(content).hexdigest() is compared against that checksum. The exception fires when they differ. This occurs when the mirror's package pool has been updated but the Packages.gz index is stale (or vice versa), when a CDN edge node serves a mismatched file, or when network corruption alters bytes in transit (rare with TCP but possible with proxy tampering).

Common situations: Mirror index and package pool are out of sync after a partial mirror update; a CDN or caching proxy serves a different version of the .deb than the index references; running against a Debian ports mirror (e.g. for loongarch64, riscv64) that lags behind; a corporate proxy that strips or rewrites content; disk corruption on the mirror; the mirror rotated packages between index fetch and deb download (race condition during active suite migration).

Related errors


AI-assisted analysis of dotnet/yarp@bd11867bee (2026-08-13). Data as JSON: /api/errors/9ac76192b0749b6f. Report an issue: GitHub.