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 v2 and above
What it means
Thrown by DefaultRecordBatch.computeAttributes when timestampType equals TimestampType.NO_TIMESTAMP_TYPE. The v2 batch attributes byte encodes, among other things, whether timestamps are CREATE_TIME or LOG_APPEND_TIME; a writer must decide one before serializing, so 'no type' is rejected. IllegalArgumentException from the producer/broker write path.
Source
Thrown at clients/src/main/java/org/apache/kafka/common/record/internal/DefaultRecordBatch.java:427
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
DefaultRecordBatch that = (DefaultRecordBatch) o;
return Objects.equals(buffer, that.buffer);
}
@Override
public int hashCode() {
return buffer != null ? buffer.hashCode() : 0;
}
private static byte computeAttributes(CompressionType type, TimestampType timestampType,
boolean isTransactional, boolean isControl, boolean isDeleteHorizonSet) {
if (timestampType == TimestampType.NO_TIMESTAMP_TYPE)
throw new IllegalArgumentException("Timestamp type must be provided to compute attributes for message " +
"format v2 and above");
byte attributes = isTransactional ? TRANSACTIONAL_FLAG_MASK : 0;
if (isControl)
attributes |= CONTROL_FLAG_MASK;
if (type.id > 0)
attributes |= (byte) (COMPRESSION_CODEC_MASK & type.id);
if (timestampType == TimestampType.LOG_APPEND_TIME)
attributes |= TIMESTAMP_TYPE_MASK;
if (isDeleteHorizonSet)
attributes |= DELETE_HORIZON_FLAG_MASK;
return attributes;
}
public static void writeEmptyHeader(ByteBuffer buffer,
byte magic,
long producerId,
short producerEpoch,View on GitHub (pinned to c31c9215e1)
Solutions
- Pass an explicit TimestampType.CREATE_TIME or TimestampType.LOG_APPEND_TIME to the builder/writeHeader call.
- Prefer the high-level MemoryRecords.builder(...) factories, which default to a valid TimestampType, over writeHeader directly.
- If the choice should depend on broker config (message.timestamp.type), read that config and forward the resolved TimestampType rather than NO_TIMESTAMP_TYPE.
Example fix
// before
writeHeader(buf, baseOffset, delta, size, magic,
compression, TimestampType.NO_TIMESTAMP_TYPE, ...);
// after
TimestampType type = afterLogAppend ? TimestampType.LOG_APPEND_TIME
: TimestampType.CREATE_TIME;
writeHeader(buf, baseOffset, delta, size, magic, compression, type, ...); Defensive patterns
Strategy: validation
Validate before calling
// This is an internal writer path (computeAttributes), reached only when constructing v2+
// batches. End users normally don't call it directly, but custom MemoryRecordsBuilder users
// must pass a non-NO_TIMESTAMP_TYPE:
TimestampType requireTimestampType(TimestampType t) {
if (t == null || t == TimestampType.NO_TIMESTAMP_TYPE)
throw new IllegalArgumentException("TimestampType required for v2 batches; use CREATE_TIME or LOG_APPEND_TIME");
return t;
} Type guard
// Narrow to a non-null, meaningful type at API boundaries:
static final class ResolvedTimestampType {
private final TimestampType t;
private ResolvedTimestampType(TimestampType t) { this.t = t; }
static ResolvedTimestampType of(TimestampType in) {
if (in == TimestampType.NO_TIMESTAMP_TYPE)
throw new IllegalArgumentException("resolve to CREATE_TIME/LOG_APPEND_TIME first");
return new ResolvedTimestampType(in);
}
TimestampType get() { return t; }
} Try / catch
// Defensive guard if you build batches with pluggable timestamp policies:
try {
writeHeader(buf, ..., timestampType, ...);
} catch (IllegalArgumentException e) { // missing timestamp type
log.warn("Timestamp policy returned NO_TIMESTAMP_TYPE; defaulting to CREATE_TIME", e);
writeHeader(buf, ..., TimestampType.CREATE_TIME, ...);
} Prevention
- NO_TIMESTAMP_TYPE is a sentinel for legacy v0/v1 batches; v2+ requires an explicit CREATE_TIME or LOG_APPEND_TIME.
- If your timestamp source is dynamic (broker vs client), resolve it once at produce time, not lazily inside the batch writer.
- Unit-test your batch builder with both CREATE_TIME and LOG_APPEND_TIME to catch this before deployment.
When it happens
Trigger: Produced when writeHeader/computeAttributes is invoked with TimestampType.NO_TIMESTAMP_TYPE — typically a test helper or custom MemoryRecordsBuilder invocation that did not pin a timestamp type. Broker-side, the append path always sets LOG_APPEND_TIME or carries the producer's CREATE_TIME, so hitting this from production code implies a misconfigured builder.
Common situations: Unit tests that hand-roll batches via DefaultRecordBatch.writeHeader and pass the default TimestampType; custom tools that build control batches or tombstones without setting timestampType; integrations that conditionally omit the timestamp type when 'not appending time'.
Related errors
- Invalid message timestamp {}
- Invalid timestamp: %d. Timestamp should always be non-negati
- Invalid magic value {}
- Found invalid record count {} in magic v{} batch
- Invalid configuration value for 'acks': {acksString}
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/8f2216283e6b84ac.json.
Report an issue: GitHub.