{"id":"dba2776247ead735","repo":"apache/kafka","slug":"reserved3-field-must-be-0","errorCode":null,"errorMessage":"Reserved3 field must be 0","messagePattern":"Reserved3 field must be 0","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/compress/Lz4BlockOutputStream.java","lineNumber":375,"sourceCode":"        }\n\n        public static BD fromByte(byte bd) {\n            int reserved2 = (bd >>> 0) & 15;\n            int blockMaximumSize = (bd >>> 4) & 7;\n            int reserved3 = (bd >>> 7) & 1;\n\n            return new BD(reserved2, blockMaximumSize, reserved3);\n        }\n\n        private void validate() {\n            if (reserved2 != 0) {\n                throw new RuntimeException(\"Reserved2 field must be 0\");\n            }\n            if (blockSizeValue < 4 || blockSizeValue > 7) {\n                throw new RuntimeException(\"Block size value must be between 4 and 7\");\n            }\n            if (reserved3 != 0) {\n                throw new RuntimeException(\"Reserved3 field must be 0\");\n            }\n        }\n\n        // 2^(2n+8)\n        public int getBlockMaximumSize() {\n            return 1 << ((2 * blockSizeValue) + 8);\n        }\n\n        public byte toByte() {\n            return (byte) (((reserved2 & 15) << 0) | ((blockSizeValue & 7) << 4) | ((reserved3 & 1) << 7));\n        }\n    }\n\n}\n","sourceCodeStart":357,"sourceCodeEnd":390,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/compress/Lz4BlockOutputStream.java#L357-L390","documentation":"Thrown by BD.validate() in Lz4BlockOutputStream when the reserved3 bit (bit 7 of the BD byte) of an LZ4 frame's Block Descriptor is non-zero. The LZ4 v1.5.1 frame format reserves that bit as 0 for future use; a set bit means the frame is non-conformant. It is an unchecked RuntimeException produced while parsing the header via BD.fromByte(byte) during decompression, indicating the byte being read is not actually a valid LZ4 frame header.","triggerScenarios":"Lz4BlockInputStream (or Kafka's LZ4 decompressor invoked from MemoryRecordsBuilder/RecordsIterator) reads the BD byte from a compressed record batch and bit 7 is set. This happens when the input is not an LZ4 frame at all (e.g. garbage, snappy/gzip bytes mislabeled as LZ4), the byte stream is misaligned (offset shifted so BD is read from the wrong position), or the frame is truncated/corrupted on the wire or on disk.","commonSituations":"See trigger scenarios.","solutions":["Confirm the batch was actually produced with LZ4 compression (check producer compression.type and the record batch attributes byte); a mismatch with snappy/gzip/zstd produces this.","Re-fetch the batch from the broker; transient network corruption or partial reads commonly cause it.","If persistent, examine the segment on the broker for corruption and verify producer/broker/client Kafka versions are compatible.","Dump the raw bytes around the BD position and check frame alignment against the LZ4 frame format (magic 0x184D2204 must precede FLG/BD)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Validate the reserved bits of the LZ4 BD byte before handing the buffer to the decompressor.\nboolean lz4BdReservedBitsClear(byte bd) {\n    return (bd & 0x0F) == 0          // reserved2 (low nibble)\n        && ((bd >>> 7) & 0x01) == 0; // reserved3 (high bit)\n}","typeGuard":null,"tryCatchPattern":"// Same shape as 320: thrown from Lz4BlockInputStream.BD.validate() on a non-zero reserved bit.\ntry {\n    InputStream in = compression.wrapForInput(buffer, messageVersion, bufferSupplier);\n    // ...read...\n} catch (org.apache.kafka.common.KafkaException ke) {\n    Throwable c = ke.getCause();\n    if (c != null && c.getMessage() != null && c.getMessage().startsWith(\"Reserved\")) {\n        handleCorruptFrame(buffer); // skip / DLQ / advance offset\n    } else {\n        throw ke;\n    }\n}","preventionTips":["A non-zero reserved bit means the frame was produced by a non-conformant or future LZ4 implementation; treat the record as corrupt.","Do not attempt to 'repair' the byte — discard and move on.","Log the full frame header to detect systemic producer/version skew if it repeats."],"tags":["compression","lz4","decompression","kafka-client","data-corruption"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}