{"id":"bf18ce7889688cd9","repo":"apache/kafka","slug":"timestamp-type-must-be-provided-to-compute-attribu-bf18ce","errorCode":null,"errorMessage":"Timestamp type must be provided to compute attributes for message format v1","messagePattern":"Timestamp type must be provided to compute attributes for message format v1","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/record/internal/LegacyRecord.java","lineNumber":495,"sourceCode":"        }\n    }\n\n    static int recordSize(byte magic, ByteBuffer key, ByteBuffer value) {\n        return recordSize(magic, key == null ? 0 : key.limit(), value == null ? 0 : value.limit());\n    }\n\n    public static int recordSize(byte magic, int keySize, int valueSize) {\n        return recordOverhead(magic) + keySize + valueSize;\n    }\n\n    // visible only for testing\n    public static byte computeAttributes(byte magic, CompressionType type, TimestampType timestampType) {\n        byte attributes = 0;\n        if (type.id > 0)\n            attributes |= (byte) (COMPRESSION_CODEC_MASK & type.id);\n        if (magic > RecordBatch.MAGIC_VALUE_V0) {\n            if (timestampType == TimestampType.NO_TIMESTAMP_TYPE)\n                throw new IllegalArgumentException(\"Timestamp type must be provided to compute attributes for \" +\n                        \"message format v1\");\n            if (timestampType == TimestampType.LOG_APPEND_TIME)\n                attributes |= TIMESTAMP_TYPE_MASK;\n        }\n        return attributes;\n    }\n\n    // visible only for testing\n    public static long computeChecksum(byte magic, byte attributes, long timestamp, byte[] key, byte[] value) {\n        return computeChecksum(magic, attributes, timestamp, wrapNullable(key), wrapNullable(value));\n    }\n\n    private static long crc32(ByteBuffer buffer, int offset, int size) {\n        CRC32 crc = new CRC32();\n        Checksums.update(crc, buffer, offset, size);\n        return crc.getValue();\n    }\n","sourceCodeStart":477,"sourceCodeEnd":513,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/record/internal/LegacyRecord.java#L477-L513","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nbyte attrs = LegacyRecord.computeAttributes(RecordBatch.MAGIC_VALUE_V1, CompressionType.NONE, TimestampType.NO_TIMESTAMP_TYPE);\n// after\nbyte attrs = LegacyRecord.computeAttributes(RecordBatch.MAGIC_VALUE_V1, CompressionType.NONE, TimestampType.CREATE_TIME);","handlingStrategy":"validation","validationCode":"// computeAttributes requires a concrete TimestampType when magic == V1.\nbyte magic = RecordBatch.MAGIC_VALUE_V1;\nif (magic > RecordBatch.MAGIC_VALUE_V0\n        && (timestampType == null || timestampType == TimestampType.NO_TIMESTAMP_TYPE)) {\n    throw new IllegalArgumentException(\n        \"TimestampType.CREATE_TIME or LOG_APPEND_TIME is required for magic v1\");\n}","typeGuard":"// Narrow TimestampType to one of the two legal v1 values.\nstatic boolean isValidV1TimestampType(TimestampType t) {\n    return t == TimestampType.CREATE_TIME || t == TimestampType.LOG_APPEND_TIME;\n}","tryCatchPattern":"try {\n    byte attrs = LegacyRecord.computeAttributes(magic, compression, timestampType);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Timestamp type must be provided\")) {\n        // Default to CREATE_TIME for v1 records rather than failing the produce path.\n        timestampType = TimestampType.CREATE_TIME;\n        attrs = LegacyRecord.computeAttributes(magic, compression, timestampType);\n    } else {\n        throw e;\n    }\n}","preventionTips":["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."],"tags":["kafka","records","serialization","attributes","legacy"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}