denoland/deno · critical

checksum mismatch for {archive} (downloaded from {url})\n e

Error message

checksum mismatch for {archive} (downloaded from {url})\n  expected: {expected_lc}\n  actual:   {actual}

What it means

Thrown while fetching the LAUFEY backend runtime archive: the SHA-256 of the downloaded bytes does not match the pinned expected hash for that archive. The message deliberately includes the download URL because a poisoned redirect would otherwise be invisible in the failure log. Causes range from a truncated/corrupted transfer (proxy, flaky network) to a tampered or mis-pinned release.

Source

Thrown at cli/tools/desktop.rs:1994

      env!("CARGO_PKG_VERSION")
    )) {
      headers.insert(http::header::USER_AGENT, ua);
    }
    let response = client
      .download_with_progress_and_retries(url.clone(), &headers, &progress)
      .await
      .with_context(|| format!("failed to download {url}"))?;
    let data = response
      .into_maybe_bytes()?
      .ok_or_else(|| deno_core::anyhow::anyhow!("empty response from {url}"))?;

    let actual =
      faster_hex::hex_string(&sha2::Sha256::digest(&data)).to_lowercase();
    let expected_lc = expected.to_lowercase();
    if actual != expected_lc {
      // Include the URL in the bail: an attacker who poisoned a redirect
      // would otherwise be invisible in the failure log.
      bail!(
        "checksum mismatch for {archive} (downloaded from {url})\n  expected: {expected_lc}\n  actual:   {actual}"
      );
    }

    let parent = dir.parent().ok_or_else(|| {
      deno_core::anyhow::anyhow!(
        "LAUFEY cache dir has no parent: {}",
        dir.display()
      )
    })?;
    std::fs::create_dir_all(parent)?;

    // Stage extraction in a sibling tempdir so concurrent `deno desktop`
    // builds don't see (or stomp on) a half-populated `dir` while one
    // is mid-extract. tempfile's cleanup-on-drop covers panic /
    // early-return paths; on the happy path we consume the TempDir via
    // `into_path` so the rename below sees a real directory.
    let staging = tempfile::Builder::new()

View on GitHub (pinned to f7822238ca)

Solutions

  1. Retry the build — transient truncation is the most common cause; the cached partial file is replaced on the next attempt.
  2. Download the URL from the error message manually and compare: `curl -L <url> | sha256sum` against the `expected:` value to distinguish network corruption from a bad pin.
  3. Check proxy/SSL-inspection and free disk space in the cache dir; fix and re-run.
  4. If the hash reproducibly mismatches the official release asset, report it to the deno/laufey maintainers — it may indicate a compromised or re-cut release.

Example fix

# before
deno desktop main.ts   # checksum mismatch for laufey-cef-...tar.gz

# after (verify what the network actually delivers, then retry)
curl -sL <url-from-error> | sha256sum   # compare to expected: value
rm -rf ~/.cache/deno-desktop-laufey     # clear partial download
deno desktop main.ts
Defensive patterns

Strategy: retry

Validate before calling

# bash: pre-verify the release asset hash matches the pin before building
curl -sL "<laufey-release-url>" -o /tmp/laufey.tar.gz
ACTUAL="$(sha256sum /tmp/laufey.tar.gz | cut -d' ' -f1)"
[[ "$ACTUAL" == "<expected-sha256>" ]] || { echo "upstream hash drifted" >&2; exit 1; }

Try / catch

# Wrap the build; retry transient truncation once, escalate on repeat
set +e; deno desktop main.ts 2>&1 | tee build.log; RC=${PIPESTATUS[0]}; set -e
if [[ $RC -ne 0 ]] && grep -q "checksum mismatch" build.log; then
  rm -rf "$HOME/.cache/deno-desktop-laufey"
  deno desktop main.ts || { echo "persistent checksum mismatch — possible tampering" >&2; exit 1; }
fi

Prevention

When it happens

Trigger: Corporate proxy or flaky CDN returning a partial body or an HTML error page; a MITM rewriting the download; the pinned hash in this Deno version not matching the actual laufey release asset after an upstream re-release; disk-full truncating the written cache file.

Common situations: First build behind a captive/SSL-inspecting proxy; CI runner with an unstable network; laufey release tag re-uploaded with different assets; a full disk in the cache directory.

Related errors


AI-assisted analysis of denoland/deno@f7822238ca (2026-08-20). Data as JSON: /api/errors/d8b102b863b2ca8d. Report an issue: GitHub.