{"id":"6ad106f4aac5e434","repo":"apache/kafka","slug":"record-is-corrupt-stored-crc-computed-crc","errorCode":null,"errorMessage":"Record is corrupt (stored crc = {}, computed crc = {})","messagePattern":"Record is corrupt \\(stored crc = (.+?), computed crc = (.+?)\\)","errorType":"exception","errorClass":"CorruptRecordException","httpStatus":null,"severity":"critical","filePath":"clients/src/main/java/org/apache/kafka/common/record/internal/DefaultRecordBatch.java","lineNumber":157,"sourceCode":"    private final ByteBuffer buffer;\n\n    DefaultRecordBatch(ByteBuffer buffer) {\n        this.buffer = buffer;\n    }\n\n    @Override\n    public byte magic() {\n        return buffer.get(MAGIC_OFFSET);\n    }\n\n    @Override\n    public void ensureValid() {\n        if (sizeInBytes() < RECORD_BATCH_OVERHEAD)\n            throw new CorruptRecordException(\"Record batch is corrupt (the size \" + sizeInBytes() +\n                    \" is smaller than the minimum allowed overhead \" + RECORD_BATCH_OVERHEAD + \")\");\n\n        if (!isValid())\n            throw new CorruptRecordException(\"Record is corrupt (stored crc = \" + checksum()\n                    + \", computed crc = \" + computeChecksum() + \")\");\n    }\n\n    /**\n     * Gets the base timestamp of the batch which is used to calculate the record timestamps from the deltas.\n     *\n     * @return The base timestamp\n     */\n    public long baseTimestamp() {\n        return buffer.getLong(BASE_TIMESTAMP_OFFSET);\n    }\n\n    @Override\n    public long maxTimestamp() {\n        return buffer.getLong(MAX_TIMESTAMP_OFFSET);\n    }\n\n    @Override","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/record/internal/DefaultRecordBatch.java#L139-L175","documentation":"Thrown by DefaultRecordBatch.ensureValid when the batch's stored CRC32C (in the header) does not equal the freshly computed CRC32C over the batch body. The v2 batch carries a CRC the producer computes; any byte divergence between what was produced and what is now in the buffer makes ensureValid reject it. CorruptRecordException.","triggerScenarios":"Produced on the broker append path (Log.append / validateMessagesAndAssignOffsets), in consumer/fetch validation, and during log recovery when the bytes under the CRC field have been altered or partially overwritten. Typical: silent disk corruption, RAM bit-flips, a non-Kafka writer modifying batch bytes, or a JVM/library bug double-wrapping/altering the buffer after CRC computation.","commonSituations":"Faulty disk or failing DIMM causing bit rot on a cold segment; memcpy/zero-copy bug in a custom producer that rewrites a field after the CRC was set; compression library version skew where a recompressed body no longer matches the producer's CRC; partial-page writes after a power loss.","solutions":["Confirm whether corruption is isolated to one batch/segment with kafka-dump-log --deep-iteration; if so, drop/replay that segment.","Run hardware diagnostics (memtest, smartctl long test, fsck) — recurring CRC mismatches across topics strongly indicate failing RAM or disk.","Ensure no code path mutates the batch buffer after MemoryRecordsBuilder closes it (the CRC is finalized at close); check custom interceptors/serializers and zero-copy paths.","Align producer/broker/client compression library versions (e.g. lz4-java, snappy, zstd-jni) so decompressed bytes match what was compressed at produce time."],"exampleFix":"// before: mutating the batch buffer after the builder has computed the CRC\nbuilder.close();\nbatchBuf.putInt(BASE_OFFSET_OFFSET, newOffset); // CRC now stale\n\n// after: rebuild via the builder so CRC is recomputed after all fields are set\nMemoryRecordsBuilder b = MemoryRecords.builder(buf, magic, compression,\n    timestampType, baseOffset);\nb.append(...); // b.close() finalizes CRC once all fields are correct","handlingStrategy":"try-catch","validationCode":"// CRC mismatch is detected during ensureValid() on a buffer already on the wire/disk.\n// There is nothing to validate before the call — the CRC is recomputed internally.\n// The only preventive measure is to ensure your producer side is the one writing CRCs\n// (never bypass KafkaProducer / MemoryRecords builder).","typeGuard":null,"tryCatchPattern":"// Distinguish CRC corruption (skip) from transient fetch failures (retry):\ntry {\n    for (RecordBatch b : records) b.ensureValid();\n} catch (CorruptRecordException e) { // CRC mismatch\n    log.error(\"CRC failure on {} @ {} — likely bit-rot or tampering\", partition, offset, e);\n    alert(CRC_FAILURE, partition, offset);\n    consumer.seek(partition, offset + 1);\n}","preventionTips":["Recurring CRC errors on the same offset almost always mean a bad disk on the broker or memory corruption on the client host — run memtest and check broker SMART stats.","Do not disable CRC: never set produce acks to bypass the record-batch CRC, and never manually edit segment files.","Keep the JVM heap stable; OOM-induced truncated buffers during decompression can surface as CRC mismatches."],"tags":["kafka","record-format","crc","corruption","broker","hardware"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}