{"id":"8f2216283e6b84ac","repo":"apache/kafka","slug":"timestamp-type-must-be-provided-to-compute-attribu","errorCode":null,"errorMessage":"Timestamp type must be provided to compute attributes for message format v2 and above","messagePattern":"Timestamp type must be provided to compute attributes for message format v2 and above","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/record/internal/DefaultRecordBatch.java","lineNumber":427,"sourceCode":"    public boolean equals(Object o) {\n        if (this == o)\n            return true;\n        if (o == null || getClass() != o.getClass())\n            return false;\n\n        DefaultRecordBatch that = (DefaultRecordBatch) o;\n        return Objects.equals(buffer, that.buffer);\n    }\n\n    @Override\n    public int hashCode() {\n        return buffer != null ? buffer.hashCode() : 0;\n    }\n\n    private static byte computeAttributes(CompressionType type, TimestampType timestampType,\n                                          boolean isTransactional, boolean isControl, boolean isDeleteHorizonSet) {\n        if (timestampType == TimestampType.NO_TIMESTAMP_TYPE)\n            throw new IllegalArgumentException(\"Timestamp type must be provided to compute attributes for message \" +\n                    \"format v2 and above\");\n\n        byte attributes = isTransactional ? TRANSACTIONAL_FLAG_MASK : 0;\n        if (isControl)\n            attributes |= CONTROL_FLAG_MASK;\n        if (type.id > 0)\n            attributes |= (byte) (COMPRESSION_CODEC_MASK & type.id);\n        if (timestampType == TimestampType.LOG_APPEND_TIME)\n            attributes |= TIMESTAMP_TYPE_MASK;\n        if (isDeleteHorizonSet)\n            attributes |= DELETE_HORIZON_FLAG_MASK;\n        return attributes;\n    }\n\n    public static void writeEmptyHeader(ByteBuffer buffer,\n                                        byte magic,\n                                        long producerId,\n                                        short producerEpoch,","sourceCodeStart":409,"sourceCodeEnd":445,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/record/internal/DefaultRecordBatch.java#L409-L445","documentation":"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.","triggerScenarios":"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.","commonSituations":"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'.","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."],"exampleFix":"// before\nwriteHeader(buf, baseOffset, delta, size, magic,\n    compression, TimestampType.NO_TIMESTAMP_TYPE, ...);\n\n// after\nTimestampType type = afterLogAppend ? TimestampType.LOG_APPEND_TIME\n                                    : TimestampType.CREATE_TIME;\nwriteHeader(buf, baseOffset, delta, size, magic, compression, type, ...);","handlingStrategy":"validation","validationCode":"// This is an internal writer path (computeAttributes), reached only when constructing v2+\n// batches. End users normally don't call it directly, but custom MemoryRecordsBuilder users\n// must pass a non-NO_TIMESTAMP_TYPE:\nTimestampType requireTimestampType(TimestampType t) {\n    if (t == null || t == TimestampType.NO_TIMESTAMP_TYPE)\n        throw new IllegalArgumentException(\"TimestampType required for v2 batches; use CREATE_TIME or LOG_APPEND_TIME\");\n    return t;\n}","typeGuard":"// Narrow to a non-null, meaningful type at API boundaries:\nstatic final class ResolvedTimestampType {\n    private final TimestampType t;\n    private ResolvedTimestampType(TimestampType t) { this.t = t; }\n    static ResolvedTimestampType of(TimestampType in) {\n        if (in == TimestampType.NO_TIMESTAMP_TYPE)\n            throw new IllegalArgumentException(\"resolve to CREATE_TIME/LOG_APPEND_TIME first\");\n        return new ResolvedTimestampType(in);\n    }\n    TimestampType get() { return t; }\n}","tryCatchPattern":"// Defensive guard if you build batches with pluggable timestamp policies:\ntry {\n    writeHeader(buf, ..., timestampType, ...);\n} catch (IllegalArgumentException e) { // missing timestamp type\n    log.warn(\"Timestamp policy returned NO_TIMESTAMP_TYPE; defaulting to CREATE_TIME\", e);\n    writeHeader(buf, ..., TimestampType.CREATE_TIME, ...);\n}","preventionTips":["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."],"tags":["kafka","record-format","producer","broker","timestamp","validation"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}