apache/cassandra · critical · IOException

Checksum didn't match (expected: %d, actual: %d)

Error message

Checksum didn't match (expected: %d, actual: %d)

What it means

During compressed streaming, each chunk carries an Adler/CRC checksum computed by the sender. maybeValidateChecksum recomputes it over the decompressed buffer and compares; on mismatch it throws IOException because the decompressed data is corrupt or was mangled in transit. This protects streaming integrity across the network.

Source

Thrown at src/java/org/apache/cassandra/db/streaming/CompressedInputStream.java:206

            copyArray = new byte[max((int)(copyArray.length * GROWTH_FACTOR), dst.remaining())];

        input.readFully(copyArray, 0, dst.remaining());
        dst.put(copyArray, 0, dst.remaining());
    }
    private byte[] copyArray;

    private void maybeValidateChecksum(ByteBuffer buffer, int expectedChecksum) throws IOException
    {
        double validateChance = validateChecksumChance.getAsDouble();

        if (validateChance >= 1.0d || (validateChance > 0.0d && validateChance > ThreadLocalRandom.current().nextDouble()))
        {
            int position = buffer.position();
            int actualChecksum = (int) checksumType.of(buffer);
            buffer.position(position); // checksum calculation consumes the buffer, so we must reset its position afterwards

            if (expectedChecksum != actualChecksum)
                throw new IOException(format("Checksum didn't match (expected: %d, actual: %d)", expectedChecksum, actualChecksum));
        }
    }

    @Override
    public void close()
    {
        if (null != buffer)
        {
            MemoryUtil.clean(buffer);
            buffer = null;
        }

        if (null != compressedChunk)
        {
            MemoryUtil.clean(compressedChunk);
            compressedChunk = null;
        }
    }

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Retry the streaming session — checksum failures are usually transient corruption
  2. Run nodetool scrub / verify on the sending node's SSTables to detect on-disk corruption
  3. Check network hardware and disable/inspect any middleboxes altering payloads
  4. Verify compression parameters and Cassandra versions match on both endpoints
  5. Check dmesg/hardware logs for disk or memory errors

Example fix

// before
// no retry on IOException from stream read
stream.position(pos);
// after
try {
    stream.position(pos);
} catch (IOException e) {
    if (e.getMessage().startsWith("Checksum didn't match"))
        retryStreamSession(); // re-initiate the failed range
    else
        throw e;
}
Defensive patterns

Strategy: retry

Try / catch

try { readStream(); } catch (IOException e) { if (e.getMessage().contains("Checksum didn't match")) retrySession(); else throw e; }

Prevention

When it happens

Trigger: Receiving a compressed chunk whose recomputed checksum differs from the expected checksum sent alongside it — network bit corruption, a buggy/misconfigured compression compressor mismatch, or a partial chunk write followed by reuse of a buffer.

Common situations: Faulty NIC/cable/disk causing silent bit flips during streaming; intercepting proxies or encryption layers corrupting payloads; custom compression parameters changed on one node; hardware faults (bad RAM) on the sender.

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 apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/f30f21bb3f2c8170. Report an issue: GitHub.