apache/cassandra · critical · IOException

Round-trip mismatch: compressed with

Error message

Round-trip mismatch: compressed with %s, decompressed with %s

What it means

During the compression provider smoke test, a payload compressed by the provider's compressor is decompressed by the built-in (or vice versa) and compared to the original. If decompression yields different bytes, an IOException 'Round-trip mismatch' is thrown, indicating the provider's codec is not interoperable with the built-in it substitutes for.

Solutions

  1. Fix the provider's compress/uncompress so the built-in can decompress its output byte-identically (and vice versa)
  2. Compare output buffers byte-by-byte with the reported inputs to locate the first differing byte
  3. Test with the seeded smokeTestPayload payloads used by StartupChecks
  4. Drop the provider registration if true interoperability cannot be achieved

Example fix

// before
output.flip(); return output; // leftover padding bytes included in comparison
// after
output.flip();
output.limit(uncompressedSize); // only the actual payload bytes
return output;
Defensive patterns

Strategy: validation

Validate before calling

byte[] c = provider.uncompress(builtin.compress(payload)); assert Arrays.equals(c, payload); // and the reverse direction

Prevention

When it happens

Trigger: assertCompatibleRoundTrip(): compress with compressor, uncompress with decompressor, output ByteBuffer != ByteBuffer.wrap(payload) — for deterministic seeded payloads.

Common situations: Provider codec produces a valid-but-different format, trailing bytes/padding handled differently, provider truncated or padded the buffer differently than the built-in expects.

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/6d3ed9ffcc930607. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/service/StartupChecks.java:486

            compressed.flip();

            // Within a compress/uncompress call the in/out buffers must share a type, but the compressor
            // and decompressor may prefer different ones; only re-stage the compressed bytes in that case.
            if (compressor.preferredBufferType() != decompressor.preferredBufferType())
            {
                ByteBuffer staged = decompressor.preferredBufferType().allocate(compressed.remaining());
                staged.put(compressed);
                staged.flip();
                compressed = staged;
            }

            ByteBuffer output = decompressor.preferredBufferType().allocate(payload.length);
            decompressor.uncompress(compressed, output);
            output.flip();

            if (!output.equals(ByteBuffer.wrap(payload)))
            {
                throw new IOException(String.format("Round-trip mismatch: compressed with %s, decompressed with %s",
                                                    compressor.getClass().getName(), decompressor.getClass().getName()));
            }
        }
        private byte[] smokeTestPayload(Random random)
        {
            // 4 KiB payload: the first half zeros (highly compressible, exercises the real compression
            // path), the second half high-entropy bytes (incompressible, exercises the compressor's
            // worst-case output sizing via initialCompressedBufferLength).
            byte[] testPayload = new byte[4 * 1024];
            byte[] randomHalf = new byte[testPayload.length / 2];
            random.nextBytes(randomHalf);
            System.arraycopy(randomHalf, 0, testPayload, testPayload.length / 2, randomHalf.length);
            return testPayload;
        }
    };

    public static final StartupCheck checkValidLaunchDate = new StartupCheck()
    {

View on GitHub (pinned to 88fd0f6a0e)