coleam00/Archon · critical

Checksum mismatch: expected ${expectedHash}, got ${actualHas

Error message

Checksum mismatch: expected ${expectedHash}, got ${actualHash}

What it means

After downloading archon-web.tar.gz, downloadWebDist hashes the tarball with Bun.CryptoHasher (sha256) and compares it to the expected hash resolved from the published checksums.txt (parseChecksum). A mismatch means the downloaded bytes differ from the release the checksums file describes, so the tarball is rejected before extraction. This protects against truncated/corrupt downloads and compromised or mismatched artifacts.

Source

Thrown at packages/cli/src/commands/serve.ts:172

    }
    const checksumsText = await checksumsRes.text();
    expectedHash = parseChecksum(checksumsText, 'archon-web.tar.gz');
    log.info({ source: 'remote' }, 'web_dist.checksum_resolved');
    tarballRes = fetchedTarballRes;
  }

  if (!tarballRes.ok) {
    throw new Error(`Failed to download web UI: ${tarballRes.status} ${tarballRes.statusText}`);
  }
  const tarballBuffer = await tarballRes.arrayBuffer();

  // Verify checksum
  const hasher = new Bun.CryptoHasher('sha256');
  hasher.update(new Uint8Array(tarballBuffer));
  const actualHash = hasher.digest('hex');

  if (actualHash !== expectedHash) {
    throw new Error(`Checksum mismatch: expected ${expectedHash}, got ${actualHash}`);
  }
  console.log('Checksum verified.');
  const verifiedAt = performance.now();
  log.info({ durationMs: Math.round(verifiedAt - downloadStartedAt) }, 'web_dist.tarball_verified');

  // Extract to temp dir, then atomic rename
  const tmpDir = `${targetDir}.tmp`;
  const tarballPath = `${tmpDir}.tar.gz`;

  // Clean up any previous failed attempt
  rmSync(tmpDir, { recursive: true, force: true });
  mkdirSync(tmpDir, { recursive: true });

  // Stage the archive on disk so `tar` inherits a file descriptor. Passing the
  // bytes as `stdin` instead makes the parent own a channel it has to pump and
  // close, and on windows that pump can stall with no upper bound: two spawns in
  // one process sat with `tar` blocked on an unfed stdin until the test runner
  // killed them, on a runner where the same extraction took 16 ms minutes later

View on GitHub (pinned to 0773b97458)

Solutions

  1. Delete any cached/partial download and re-fetch — most mismatches are corrupted transfers; retry the serve command.
  2. Verify which release the checksums.txt came from and ensure tarball and checksums come from the SAME release/version.
  3. Check for a proxy/AV that rewrites response bodies and bypass it for the download host.
  4. Compare the published hash manually (sha256sum on the tarball) and report upstream if the official artifact genuinely doesn't match its checksums.

Example fix

// before
tarballBuffer = await res.arrayBuffer(); // no retry on corrupt download
// after
let tarballBuffer = await res.arrayBuffer();
if (sha256(tarballBuffer) !== expectedHash) {
  tarballBuffer = await refetchTarball(); // one retry for transient corruption
  if (sha256(tarballBuffer) !== expectedHash) {
    throw new Error(`Checksum mismatch: expected ${expectedHash}, got ${actualHash}`);
  }
}
Defensive patterns

Strategy: validation

Validate before calling

import { createHash } from 'node:crypto';
const buf = Buffer.from(await res.arrayBuffer());
const actual = createHash('sha256').update(buf).digest('hex');
if (actual !== expectedHash) {
  throw new Error(`Pre-check: downloaded tarball hash ${actual} != expected ${expectedHash}; refetching from the same release tag is advised`);
}

Try / catch

try {
  await serveCommand();
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Checksum mismatch:')) {
    // purge any cached/partial artifact and retry exactly once;
    // if it mismatches again, stop — do not bypass verification.
  } else throw err;
}

Prevention

When it happens

Trigger: serveCommand -> downloadWebDist downloads the tarball, computes sha256, and it !== expectedHash parsed from checksums.txt: truncated download, interrupted connection reusing a partial buffer, CDN serving a stale/different artifact, proxy tampering, or checksums.txt and tarball fetched from mismatched versions.

Common situations: Flaky network truncating the body; a mirror or CDN cache serving an old tarball; downloading checksums.txt from release X but the tarball from a cached copy of release Y; corporate TLS-inspection proxy modifying content; disk cache corruption.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/7952ccef570410f7. Report an issue: GitHub.