ErrLookup › Background articles › Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them
Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them
Checksum mismatch, digest mismatch, or "checksum verification failed" errors appear when a library compares a hash (MD5, SHA-256, CRC32, CRC64ECMA, CRC32C) computed over data it just read, downloaded, or restored against an expected value recorded earlier — in a lockfile, a sidecar file, a release manifest, or a protocol trailer — and the two disagree. Developers hit this family when downloading release binaries and archives, restoring backups and snapshots, reading Hadoop files with .crc/.md5 sidecars, running distcp or pnpm installs, or streaming data between processes. A mismatch means the bytes in hand are not the bytes the checksum describes: corruption in transit or at rest, a stale or mismatched metadata file, configuration drift between the writer and reader, or — much more rarely — tampering.
Distilled from 100 documented records across 41 repositories.
Background
A checksum mismatch error is produced at an integrity-verification boundary: a point where a library deliberately compares a digest computed over bytes it now holds against a digest recorded when those bytes were written, published, or transferred. The comparison itself is trivial; everything interesting is in what the two sides represent. The expected value comes from somewhere else in time or space — a sidecar file next to the data (.crc files in Hadoop's ChecksumFileSystem, .md5 files verified by MD5FileUtils, SHA256SUMS in Nomad snapshots), a published manifest (Deno's upgrade .sha256 files, chezmoi's .chezmoiexternal checksum fields, Archon's checksums.txt, oh-my-pi's release manifest), a lockfile (pnpm's integrity field), a header captured earlier (the TOS connector's crc64ecma response headers), or a chained trailer in a log format (Turso's MVCC frames, waveterm's WriterChan final packet). The computed value is always fresh: the library hashes the exact bytes just read, downloaded, decrypted, or received.
The mechanisms cluster into a few shapes. Download verification is the most common: a tool streams an artifact, hashes it while streaming, and refuses to install if the digest differs from the pinned one (Deno's upgrade and laufey archives, oh-my-pi's binary digest check, Archon's web dist, ECC's release gate). Here the error is a supply-chain and transfer-integrity guard, and the bytes are usually discarded or deleted before the error propagates. At-rest verification is the second shape: storage systems recompute checksums chunk by chunk during reads — HDFS BlockSender re-CRCs each chunk against its .meta file, ChecksumFileSystem verifies 512-byte slices against the .crc sidecar — and throw with the exact failing offset, expected and computed values. These are corruption detectors, and libraries deliberately make them loud because retrying the same read keeps failing.
The third shape is protocol-level integrity: gokrazy echoes a CRC32 of bytes actually written to device storage so the Tailscale updater can compare against what it sent over HTTP; waveterm's WriterChan compares a sender-supplied SHA-256 against a locally computed running hash; Turso's MVCC log chains CRC32C from frame to frame so reordering or rewriting breaks the chain. In all three, a mismatch means bytes changed, dropped, duplicated, or arrived reordered between the two endpoints.
Finally, some mismatches are not corruption at all but comparability failures: Hadoop's MD5MD5CRC file checksum is only defined when every block used the same io.bytes.per.checksum, and its COMPOSITE_CRC mode tolerates varying chunk sizes but requires a single uniform CRC algorithm — so mixed-CRC files fail differently depending on combine mode. DistCp compares source and target checksums that are only comparable when block sizes, checksum types, and filesystem implementations line up (HDFS vs S3A). Puppet's filebucket goes furthest in interpretation: when two different byte sequences hash to the same requested digest, it suspects a hash collision (in practice, a caller overriding checksum_data) and raises rather than overwrite, deliberately omitting the path from the message. What the caller sees also varies: some errors name both digests (most), some name the file and offset (Hadoop), some include the download URL so a poisoned redirect is visible in logs (Deno's laufey check), and Deno's upgrade path even prints the Actual/Expected labels swapped — worth knowing before you trust which value is which.
Common causes
- Corrupted or truncated transfer. The most common cause across download-verification records: a dropped connection, flaky CDN, disk-full write, or proxy that returned a partial body or an HTML error page. A single retry with a fresh download resolves most cases.
- Stale or mismatched metadata paired with the data. The data and its checksum record come from different generations: a Hadoop file appended by an external tool so it outgrew its .crc coverage, a .md5 sidecar copied from another checkpoint generation, a pnpm lockfile produced against a different registry that re-packed tarballs, or Part eTags reused across upload attempts.
- Configuration or algorithm drift between writer and reader. The bytes are fine but the two sides use incomparable settings: different io.bytes.per.checksum or dfs.checksum.type across appends or clusters, fs.tos.checksum-type set to CRC64ECMA on one client and CRC32C on another, or distcp across differing block sizes and filesystems. The fix is pinning settings, not restoring data.
- Genuine at-rest corruption. Bit rot, failing disk sectors, bad RAM or disk controllers, or out-of-band modification leave on-disk bytes diverging from their recorded checksums. HDFS surfaces this per-chunk with the failing offset; the client fails over to other replicas, but if all replicas fail the data is lost and must be restored from backup.
- TLS-intercepting proxies, antivirus, or tampering. Middleboxes that rewrite HTTPS bodies corrupt downloads; man-in-the-middle substitution is the rarer, more serious variant. Deterministic mismatches on a clean connection should be verified manually (sha256sum against the published digest) and reported — never bypassed.
- Upstream re-release or bad pin. A release asset was re-uploaded after the manifest, checksums.txt, or lockfile recorded its digest, so the pinned value no longer describes the artifact being served. Verify by hashing the artifact manually and report to the maintainers if the official artifact fails its own checksum.
- Concurrent or out-of-band writers. An object overwritten between metadata capture and read (TOS connector), two processes appending to one MVCC log so the CRC chain diverges, staged multipart part files modified under __STAGING__, or interleaved stream producers (waveterm) all break the assumption that the bytes verified are the bytes the checksum describes.
What usually fixes it
- [object Object]
- [object Object]
- [object Object]
- [object Object]
- [object Object]
- [object Object]
Go deeper
- Connection failures: ECONNREFUSED, ECONNRESET, and friends — why connections get refused, reset, or dropped.
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Documented occurrences
- Existing backup and new file have different content but same checksum, %{value}. Verify existing backup and remove if incorrect. (puppetlabs/puppet)
- PUT %s: gokrazy checksum = %q; want %q (tailscale/tailscale)
- Expected checksum is %s while actual checksum is %s (apache/hadoop)
- Checksum error: {} at {} exp: {} got: {} (apache/hadoop)
- Byte-per-checksum not matched: bpc={} but bytesPerCRC={} (apache/hadoop)
- DataChecksum.Type.MIXED is not supported for COMPOSITE_CRC (apache/hadoop)
- Checksum mismatch between {} and {}. (apache/hadoop)
- Checksum verification failed. Actual: {} Expected: {} (denoland/deno)
- Checksum failed at {failedPos} for replica: {replica} (apache/hadoop)
- Checksum error: {} at {} (apache/hadoop)
- Checksum ${type} not matched for file ${filename} at position ${errPos}: expected=%X but computed=%X, algorithm=${algorithmClass} (apache/hadoop)
- plaintext file checksums do not match, expect: {:?}, calculate: {:?} (tikv/tikv)
- part etag mismatched: %s != %s (apache/hadoop)
- Downloaded binary size mismatch: expected ${options.expectedSize} bytes, received ${size} (can1357/oh-my-pi)
- Downloaded binary digest mismatch: expected ${options.expectedDigest}, received ${digest} (can1357/oh-my-pi)
- Checksum mismatch: expected ${expectedHash}, got ${actualHash} (coleam00/Archon)
- frozen human eval hash mismatch — set has drifted (got ${corpusHash}, pinned ${FROZEN_HUMAN_EVAL_HASH}); supersede with a new versioned file, do not edit (ruvnet/ruflo)
- File {} did not match stored MD5 checksum (stored: {}, computed: {} (apache/hadoop)
- ${label} digest mismatch: expected ${expectedDigest}, got ${actual}. (affaan-m/ECC)
- INVALID_PLAN_HASH: Invalid or mis-matched hash. (apache/hadoop)
…and 80 more across the corpus — use search.
Honest provenance: generated on 2026-09-04 from AI-assisted analysis of the linked records. See how records are made.