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 laterView on GitHub (pinned to 0773b97458)
Solutions
- Delete any cached/partial download and re-fetch — most mismatches are corrupted transfers; retry the serve command.
- Verify which release the checksums.txt came from and ensure tarball and checksums come from the SAME release/version.
- Check for a proxy/AV that rewrites response bodies and bypass it for the download host.
- 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
- Always fetch tarball and checksums.txt from the same release tag in the same script run.
- Avoid proxies/AV that rewrite HTTPS bodies for the download host, or allowlist it.
- Retry with a fresh connection rather than reusing cached bodies after a mismatch.
- Never disable checksum verification to 'unblock' — that converts this error into a supply-chain risk.
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
- Malformed checksum entry for ${filename}: "${line.trim()}"
- Malformed embedded checksum: "${checksum}"
- Network error fetching tarball from ${tarballUrl}: ${toError
- Network error fetching checksums from ${checksumsUrl}: ${toE
- Failed to download web UI: ${tarballRes.status} ${tarballRes
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/7952ccef570410f7.
Report an issue: GitHub.