{"id":"563eaa2f7a3dc423","repo":"apache/kafka","slug":"cannot-set-timestamp-for-a-record-with-magic-0","errorCode":null,"errorMessage":"Cannot set timestamp for a record with magic = 0","messagePattern":"Cannot set timestamp for a record with magic = 0","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/record/internal/AbstractLegacyRecordBatch.java","lineNumber":488,"sourceCode":"        @Override\n        public long offset() {\n            return buffer.getLong(OFFSET_OFFSET);\n        }\n\n        @Override\n        public LegacyRecord outerRecord() {\n            return record;\n        }\n\n        @Override\n        public void setLastOffset(long offset) {\n            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);","sourceCodeStart":470,"sourceCodeEnd":506,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/record/internal/AbstractLegacyRecordBatch.java#L470-L506","documentation":"Thrown by AbstractLegacyRecordBatch.setMaxTimestamp when the wrapped LegacyRecord has magic value 0 (the original Kafka v0 message format). V0 records carry no timestamp field at all (timestamps were introduced in v1), so any attempt to mutate the max timestamp is structurally impossible. The check guards the buffer writes in setTimestampAndUpdateCrc, which would otherwise corrupt the layout by writing a timestamp into bytes that do not exist in the v0 on-disk format.","triggerScenarios":"Calling RecordBatch.setMaxTimestamp(TimestampType, long) on an AbstractLegacyRecordBatch whose underlying LegacyRecord.magic() == RecordBatch.MAGIC_VALUE_V0 (0). This happens when broker/replication or log-recovery code attempts to apply a new max timestamp (e.g., LogValidator.assignTimestamps or rolling logic) onto a segment still containing v0 messages.","commonSituations":"Reading or rewriting very old log segments from a Kafka cluster that produced v0 messages (pre-0.10). Migration/upgrade tooling, log format conversion, or an inter-broker protocol downgrade where a newer broker is forced to handle legacy v0 segments.","solutions":["Upgrade the topic's message format to v1 or v2 (kafka-topics --alter --config message.format.version=1.0.0 or higher) so records carry timestamps.","Filter or skip v0 batches before attempting setMaxTimestamp; gate on record.magic() >= RecordBatch.MAGIC_VALUE_V1 before invoking it.","Reproduce the segment on a newer broker by re-producing the v0 data into a topic whose message.format.version is >= 0.10.0, then retire the legacy segment."],"exampleFix":"// before\nbatch.setMaxTimestamp(TimestampType.CREATE_TIME, now);\n\n// after\nif (batch.magic() >= RecordBatch.MAGIC_VALUE_V1) {\n    batch.setMaxTimestamp(TimestampType.CREATE_TIME, now);\n}","handlingStrategy":"type-guard","validationCode":"// Before calling setMaxTimestamp on a LegacyRecordBatch:\nbyte magic = batch.magic();\nif (magic == RecordBatch.MAGIC_VALUE_V0) {\n    // V0 records have no timestamp field; skip timestamp assignment\n    return;\n}","typeGuard":"// Guard: only V1+ legacy batches carry timestamps\nstatic boolean supportsTimestamp(RecordBatch b) {\n    return b.magic() >= RecordBatch.MAGIC_VALUE_V1;\n}","tryCatchPattern":"try {\n    batch.setMaxTimestamp(timestampType, ts);\n} catch (UnsupportedOperationException e) {\n    // expected for magic=0 batches; timestamp is not applicable\n}","preventionTips":["Treat magic=0 (pre-0.10) records as timestamp-less; never call setMaxTimestamp on them.","Upgrade topic message format to magic >= 1 (inter.broker.protocol.version / message.format.version) if you need timestamps.","Centralize batch mutation behind a helper that branches on batch.magic()."],"tags":["record-format","magic-v0","legacy-record","timestamp"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}