apache/kafka · error · IllegalArgumentException
Timestamp type must be provided to compute attributes for me
Error message
Timestamp type must be provided to compute attributes for message format v1
What it means
Thrown by LegacyRecord.computeAttributes() when computing the attributes byte for message format v1 (magic > MAGIC_VALUE_V0). For v1 records the timestamp type is a load-bearing attribute bit, so the caller must explicitly say whether the timestamp is CreateTime or LogAppendTime. Passing TimestampType.NO_TIMESTAMP_TYPE means the caller forgot to choose, which would silently encode an incorrect attributes byte.
Source
Thrown at clients/src/main/java/org/apache/kafka/common/record/internal/LegacyRecord.java:495
}
}
static int recordSize(byte magic, ByteBuffer key, ByteBuffer value) {
return recordSize(magic, key == null ? 0 : key.limit(), value == null ? 0 : value.limit());
}
public static int recordSize(byte magic, int keySize, int valueSize) {
return recordOverhead(magic) + keySize + valueSize;
}
// visible only for testing
public static byte computeAttributes(byte magic, CompressionType type, TimestampType timestampType) {
byte attributes = 0;
if (type.id > 0)
attributes |= (byte) (COMPRESSION_CODEC_MASK & type.id);
if (magic > RecordBatch.MAGIC_VALUE_V0) {
if (timestampType == TimestampType.NO_TIMESTAMP_TYPE)
throw new IllegalArgumentException("Timestamp type must be provided to compute attributes for " +
"message format v1");
if (timestampType == TimestampType.LOG_APPEND_TIME)
attributes |= TIMESTAMP_TYPE_MASK;
}
return attributes;
}
// visible only for testing
public static long computeChecksum(byte magic, byte attributes, long timestamp, byte[] key, byte[] value) {
return computeChecksum(magic, attributes, timestamp, wrapNullable(key), wrapNullable(value));
}
private static long crc32(ByteBuffer buffer, int offset, int size) {
CRC32 crc = new CRC32();
Checksums.update(crc, buffer, offset, size);
return crc.getValue();
}
View on GitHub (pinned to c31c9215e1)
Solutions
- Pass TimestampType.CREATE_TIME or TimestampType.LOG_APPEND_TIME explicitly when magic is v1.
- If constructing via MemoryRecordsBuilder, supply the TimestampType argument to the builder rather than relying on a default.
- For v0 records keep magic=MAGIC_VALUE_V0 so the timestamp-type bit is not required.
Example fix
// before byte attrs = LegacyRecord.computeAttributes(RecordBatch.MAGIC_VALUE_V1, CompressionType.NONE, TimestampType.NO_TIMESTAMP_TYPE); // after byte attrs = LegacyRecord.computeAttributes(RecordBatch.MAGIC_VALUE_V1, CompressionType.NONE, TimestampType.CREATE_TIME);
Defensive patterns
Strategy: validation
Validate before calling
// computeAttributes requires a concrete TimestampType when magic == V1.
byte magic = RecordBatch.MAGIC_VALUE_V1;
if (magic > RecordBatch.MAGIC_VALUE_V0
&& (timestampType == null || timestampType == TimestampType.NO_TIMESTAMP_TYPE)) {
throw new IllegalArgumentException(
"TimestampType.CREATE_TIME or LOG_APPEND_TIME is required for magic v1");
} Type guard
// Narrow TimestampType to one of the two legal v1 values.
static boolean isValidV1TimestampType(TimestampType t) {
return t == TimestampType.CREATE_TIME || t == TimestampType.LOG_APPEND_TIME;
} Try / catch
try {
byte attrs = LegacyRecord.computeAttributes(magic, compression, timestampType);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Timestamp type must be provided")) {
// Default to CREATE_TIME for v1 records rather than failing the produce path.
timestampType = TimestampType.CREATE_TIME;
attrs = LegacyRecord.computeAttributes(magic, compression, timestampType);
} else {
throw e;
}
} Prevention
- Never pass TimestampType.NO_TIMESTAMP_TYPE when constructing v1 message format batches; it is only valid for v0.
- When reading legacy records off disk, branch on magic value first and only call computeAttributes for v1 with a real TimestampType from the broker config (log.message.timestamp.type).
- Keep magic/version in lockstep with timestampType in your own data model so the pair is always consistent.
When it happens
Trigger: Calling computeAttributes(magic=RecordBatch.MAGIC_VALUE_V1, type, TimestampType.NO_TIMESTAMP_TYPE). Reached indirectly through MemoryRecordsBuilder when it is constructed for v1 without a timestamp type, or via tests/benchmarks that pass the default NO_TIMESTAMP_TYPE.
Common situations: Building a v1 MemoryRecordsBuilder without specifying TimestampType, or copying code that worked for v0 (which has no timestamp-type bit) into a v1 path. Config mistakes where a producer or test harness uses LOG_APPEND_TIME/CREATE_TIME constants inconsistently.
Related errors
- Invalid message timestamp {}
- Invalid magic used in LegacyRecord: {}
- Invalid serialized transaction state format: {serializedStat
- Invalid value null for configuration key.serializer: must be
- Invalid value null for configuration value.serializer: must
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/bf18ce7889688cd9.json.
Report an issue: GitHub.