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
- Fix the provider's compress/uncompress so the built-in can decompress its output byte-identically (and vice versa)
- Compare output buffers byte-by-byte with the reported inputs to locate the first differing byte
- Test with the seeded smokeTestPayload payloads used by StartupChecks
- 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
- Test both directions (provider->builtin and builtin->provider)
- Use the same seeded payloads as StartupChecks in provider CI
- Handle buffer limits/flip semantics exactly as the built-in does
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
- ERR_WRONG_CONFIG
- A local deletion time should not be a legacy overflowed…
- A local deletion time should not be negative
- A local deletion time should not be negative in
- A tombstone should not have a value
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)