dotnet/efcore · error · Exception

SHA256 mismatch for : expected , got

Error message

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

What it means

Raised by download_file when a caller-supplied checksum (the SHA256 from the Packages index, passed at line 61) does not match the SHA256 of the bytes actually received from the mirror. It signals a corrupted or substituted download. Note the exception is a bare Exception, so it is NOT one of the retryable types in the except tuple (CancelledError/TimeoutError/ClientError) and propagates immediately without retry.

Solutions

  1. Re-run against a different mirror (e.g. switch from a community mirror to the official one) since the most common cause is a mirror mid-publish.
  2. Verify --mirror, --suite, and --arch are a consistent, valid combination.
  3. Manually curl the failing {url}, compute sha256sum, and compare against the SHA256 field in the Packages index to confirm whether the mirror or the index is wrong.
  4. Disable any transparent HTTP proxy (HTTP_PROXY/HTTPS_PROXY, apt-cacher) and retry.
  5. If reproducible across mirrors, treat it as a potential integrity attack and investigate the source of the bytes.

Example fix

// before
if sha256 != checksum:
    raise Exception(f"SHA256 mismatch for {url}: expected {checksum}, got {sha256}")  # propagates, NOT retried

// after
if sha256 != checksum:
    raise aiohttp.ClientError(f"SHA256 mismatch for {url}: expected {checksum}, got {sha256}")  # now caught by the retry handler
Defensive patterns

Strategy: retry

Validate before calling

# preflight: confirm the mirror serves the expected bytes for one sample package
import aiohttp, asyncio, hashlib
async def verify(mirror, filename, expected):
    async with aiohttp.ClientSession() as s:
        async with s.get(f"{mirror}/{filename}") as r:
            data = await r.read()
            return hashlib.sha256(data).hexdigest() == expected
# asyncio.run(verify(args.mirror, sample_filename, sample_sha))

Try / catch

try:
    asyncio.run(download_package_index_parallel(...))
    asyncio.run(install_packages(...))
except Exception as e:
    if "SHA256 mismatch" in str(e):
        # integrity failure -> retry against a different trusted mirror, do NOT silently continue
        raise SystemExit(f"integrity failure, retry with another mirror: {e}")
    raise

Prevention

When it happens

Trigger: Calling download_file with checksum set (as download_deb_files_parallel does via info.get('SHA256')) and the body returned by {mirror}/{filename} hashes to a different value than the Packages index recorded.

Common situations: Mirror is mid-sync (inconsistent build published), CDN/cache serves a stale or different build, --mirror and --suite point to inconsistent sources, a corporate proxy or apt-cacher serves cached wrong bytes, or (rarely) a MITM altering bytes.

Related errors


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

Appendix: 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 3a2006ef56)