dotnet/efcore · error · Exception

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

Error message

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

What it means

In eng/common/cross/install-debs.py (download_file, line 20-47), each downloaded .deb file is verified against a SHA256 checksum recorded in the Debian package index. After reading the response body, hashlib.sha256 is computed (line 32) and compared to the expected checksum (line 33); on mismatch a plain Exception is raised at line 34. This protects against truncated, corrupted, or tampered downloads during rootfs construction.

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

Solutions

  1. Retry the build (download_file already retries up to max_retries=3); transient mirror desync often resolves on retry or after a short delay.
  2. Switch to a more reliable/synced mirror via --mirror (e.g. the official debian.org mirror).
  3. Clear any caching proxy in front of the build host, or bypass it.
  4. Update eng/common from the dotnet/arcade repo so package index/checksums are current.
  5. If the checksum in the index is genuinely wrong, report/verify against the distribution's published checksums.

Example fix

# before
python3 install-debs.py --mirror http://cached-proxy/debian ...

# after (use a fresh official mirror and retry)
python3 install-debs.py --mirror http://deb.debian.org/debian ...
Defensive patterns

Strategy: retry

Validate before calling

# Optionally pre-verify a URL's checksum before invoking install-debs.py,
# though the script itself is the authority. Set a reliable mirror and clean proxies:
# export no_proxy="$no_proxy,deb.debian.org"
# Then run with the official mirror to avoid stale cached artifacts.

Try / catch

try:
    asyncio.run(download_deb_files_parallel(mirror, packages, tmp_dir))
except Exception as e:
    if 'SHA256 mismatch' in str(e):
        # retry against a fresh/official mirror, or clear the caching proxy
        mirror = 'http://deb.debian.org/debian'
        asyncio.run(download_deb_files_parallel(mirror, packages, tmp_dir))
    else:
        raise

Prevention

When it happens

Trigger: A network issue (proxy cache poisoning, interrupted connection, mirror desync), a man-in-the-middle, a stale/incorrect checksum in the Packages index, or a mirror serving a different package version than its index advertises — any case where the bytes received do not hash to the expected SHA256.

Common situations: Building .NET runtime rootfs on a flaky corporate network or behind a caching proxy; a Debian/Ubuntu mirror partially updated (index newer than the .deb files); running an old checkout of eng/common against a moved mirror; clock/time issues causing TLS interception artifacts.

Related errors


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/b0270b0a48fd1da3. Report an issue: GitHub.