{"id":"034863e922c7f4aa","repo":"apache/kafka","slug":"magic-versions-prior-to-2-do-not-support-partition","errorCode":null,"errorMessage":"Magic versions prior to 2 do not support partition leader epoch","messagePattern":"Magic versions prior to 2 do not support partition leader epoch","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/record/internal/AbstractLegacyRecordBatch.java","lineNumber":500,"sourceCode":"            buffer.putLong(OFFSET_OFFSET, offset);\n        }\n\n        @Override\n        public void setMaxTimestamp(TimestampType timestampType, long timestamp) {\n            if (record.magic() == RecordBatch.MAGIC_VALUE_V0)\n                throw new UnsupportedOperationException(\"Cannot set timestamp for a record with magic = 0\");\n\n            long currentTimestamp = record.timestamp();\n            // We don't need to recompute crc if the timestamp is not updated.\n            if (record.timestampType() == timestampType && currentTimestamp == timestamp)\n                return;\n\n            setTimestampAndUpdateCrc(timestampType, timestamp);\n        }\n\n        @Override\n        public void setPartitionLeaderEpoch(int epoch) {\n            throw new UnsupportedOperationException(\"Magic versions prior to 2 do not support partition leader epoch\");\n        }\n\n        private void setTimestampAndUpdateCrc(TimestampType timestampType, long timestamp) {\n            byte attributes = LegacyRecord.computeAttributes(magic(), compressionType(), timestampType);\n            buffer.put(LOG_OVERHEAD + LegacyRecord.ATTRIBUTES_OFFSET, attributes);\n            buffer.putLong(LOG_OVERHEAD + LegacyRecord.TIMESTAMP_OFFSET, timestamp);\n            long crc = record.computeChecksum();\n            ByteUtils.writeUnsignedInt(buffer, LOG_OVERHEAD + LegacyRecord.CRC_OFFSET, crc);\n        }\n\n        /**\n         * LegacyRecordBatch does not implement this iterator and would hence fallback to the normal iterator.\n         *\n         * @return An iterator over the records contained within this batch\n         */\n        @Override\n        public CloseableIterator<Record> skipKeyValueIterator(BufferSupplier bufferSupplier) {\n            return CloseableIterator.wrap(iterator(bufferSupplier));","sourceCodeStart":482,"sourceCodeEnd":518,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/record/internal/AbstractLegacyRecordBatch.java#L482-L518","documentation":"Thrown by AbstractLegacyRecordBatch.setPartitionLeaderEpoch for any legacy batch (magic < 2). The partition leader epoch is an attribute only present in the v2 record-batch format (introduced in Kafka 0.11 / KIP-101); v0/v1 records have no field to store it. The method unconditionally throws because the operation is meaningless for the on-disk layout.","triggerScenarios":"Calling setPartitionLeaderEpoch(int) on a batch whose magic is 0 or 1 — typically in the broker's log recovery / replication path (e.g., LogValidator.assignPartitionLeaderEpoch or LogManager recovery) when it encounters a v0/v1 segment.","commonSituations":"Mixed-format topics where some segments predate v2; broker restart on an old topic whose message.format.version is still 0.10.x; replication or log recovery operating against a legacy segment after a controller failover.","solutions":["Raise the topic's message.format.version to 2.0.0 or higher (kafka-topics --alter --config message.format.version=2.0) so new batches are v2 and carry leader epoch.","Gate calls: only invoke setPartitionLeaderEpoch when batch.magic() >= RecordBatch.MAGIC_VALUE_V2.","Re-produce the legacy segment into a v2-format topic to retire pre-0.11 data."],"exampleFix":"// before\nbatch.setPartitionLeaderEpoch(epoch);\n\n// after\nif (batch.magic() >= RecordBatch.MAGIC_VALUE_V2) {\n    batch.setPartitionLeaderEpoch(epoch);\n}","handlingStrategy":"type-guard","validationCode":"// Before calling setPartitionLeaderEpoch:\nif (batch.magic() < RecordBatch.MAGIC_VALUE_V2) {\n    // leader epoch only exists on V2+ batches; skip\n    return;\n}","typeGuard":"// Guard: only V2 batches carry a partition leader epoch\nstatic boolean supportsLeaderEpoch(RecordBatch b) {\n    return b.magic() >= RecordBatch.MAGIC_VALUE_V2;\n}","tryCatchPattern":"try {\n    batch.setPartitionLeaderEpoch(epoch);\n} catch (UnsupportedOperationException e) {\n    // legacy batch (magic < 2); leader epoch not representable\n}","preventionTips":["Partition leader epoch is a V2-only concept; never call setPartitionLeaderEpoch on V0/V1 batches.","Migrate topics to message.format.version >= 2.0 (or rely on KRaft defaults) if you depend on epoch-tagged records.","Branch on magic() before any V2-specific mutation."],"tags":["record-format","leader-epoch","magic-v1","legacy-record"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}