Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Kafka Protocol Primitive Types

This document specifies the primitive data types used in the Apache Kafka binary wire protocol. All multi-byte values use big-endian (network) byte order unless otherwise specified. Implementations must encode and decode these types exactly as specified.


TypeSizeRangeEncoding
INT81 byte-128 to 127Two's complement, big-endian
INT162 bytes-32,768 to 32,767Two's complement, big-endian
INT324 bytes-2,147,483,648 to 2,147,483,647Two's complement, big-endian
INT648 bytes-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807Two's complement, big-endian

Encoding Examples:

ValueTypeBytes (hex)
0INT800
-1INT8FF
127INT87F
-128INT880
256INT1601 00
-1INT16FF FF
16909060INT3201 02 03 04
TypeSizeRangeEncoding
UINT162 bytes0 to 65,535Unsigned, big-endian
UINT324 bytes0 to 4,294,967,295Unsigned, big-endian

Unsigned Integer Usage

Unsigned integers are used sparingly in the protocol. UINT16 and UINT32 appear only in specific APIs, while UNSIGNED_VARINT is the compact length primitive.


Variable-length integers provide efficient encoding of small values while supporting the full range of 32-bit or 64-bit integers.

A variable-length encoded signed 32-bit integer using zig-zag encoding.

PropertyValue
Maximum encoded size5 bytes
Value range-2,147,483,648 to 2,147,483,647
EncodingZig-zag + variable-length

Zig-zag Transformation:

encoded = (value << 1) ^ (value >> 31)

This transformation maps signed values to unsigned values:

Signed ValueZig-zag Encoded
00
-11
12
-23
24
21474836474294967294
-21474836484294967295

Variable-Length Encoding:

After zig-zag transformation, the value is encoded using continuation bits:

  • Each byte uses 7 bits for data and 1 bit (MSB) as continuation flag
  • MSB = 1 indicates more bytes follow
  • MSB = 0 indicates final byte
Byte layout: [C][D6][D5][D4][D3][D2][D1][D0]
C = Continuation bit (1 = more bytes, 0 = last byte)
D = Data bits (7 per byte, little-endian order)

Encoding Examples:

ValueZig-zagEncoded Bytes (hex)
0000
-1101
1202
631267E
6412880 01
-6512981 01
819116382FE 7F
81921638480 80 01

Maximum Byte Length

Implementations must reject VARINT values encoded in more than 5 bytes as a protocol error. A valid VARINT must have the continuation bit clear (0) by the 5th byte.

A variable-length encoded signed 64-bit integer using zig-zag encoding.

PropertyValue
Maximum encoded size10 bytes
Value range-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
EncodingZig-zag + variable-length

Zig-zag Transformation:

encoded = (value << 1) ^ (value >> 63)

Maximum Byte Length

Implementations must reject VARLONG values encoded in more than 10 bytes as a protocol error.

A variable-length encoded unsigned 32-bit integer without zig-zag transformation.

PropertyValue
Maximum encoded size5 bytes
Value range0 to 4,294,967,295
EncodingVariable-length (no zig-zag)

Encoding Examples:

ValueEncoded Bytes (hex)
000
101
1277F
12880 01
16383FF 7F
1638480 80 01

Primary Usage:

  • Length fields in compact encodings (COMPACT_STRING, COMPACT_ARRAY, etc.)
  • Tagged field metadata
  • Flexible version headers

A double-precision 64-bit IEEE 754 floating-point number.

PropertyValue
Size8 bytes
EncodingIEEE 754 binary64, big-endian
Special valuesNaN, +Infinity, -Infinity supported

Byte Layout:

Bit 63: Sign (0 = positive, 1 = negative)
Bits 62-52: Exponent (11 bits, biased by 1023)
Bits 51-0: Mantissa (52 bits)

NaN Handling

The Kafka protocol does not mandate a specific NaN payload. When deserializing, any value with exponent bits all set and non-zero mantissa must be interpreted as NaN.


A universally unique identifier as defined in RFC 4122.

PropertyValue
Size16 bytes
EncodingBig-endian (most significant bits first)
Zero UUID16 zero bytes (sentinel in some APIs)

Byte Layout:

Bytes 0-7: Most significant 64 bits (time_low, time_mid, time_hi_and_version)
Bytes 8-15: Least significant 64 bits (clock_seq, node)

Zero UUID:

Some APIs use an all-zero UUID as a sentinel value:

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

UUID Version

The Kafka protocol does not mandate a specific UUID version.


A single-byte boolean value.

PropertyValue
Size1 byte
False0x00
TrueAny non-zero value

Encoding Rules:

RequirementLevel
Implementations should write 0x00 for falseshould
Implementations should write 0x01 for trueshould
Implementations must interpret 0x00 as falsemust
Implementations must interpret any non-zero value as truemust

A length-prefixed UTF-8 string that cannot be null.

PropertyValue
Length fieldINT16
Maximum length32,767 bytes
Null handlingNot nullable

Wire Format:

STRING => length:INT16 data:BYTES[length]

Encoding Example:

StringLengthEncoded Bytes (hex)
""000 00
"a"100 01 61
"hello"500 05 68 65 6C 6C 6F

Null Constraint

A length value of -1 must be rejected as invalid for non-nullable STRING. Implementations must not encode null values using this type.

A length-prefixed UTF-8 string that may be null.

PropertyValue
Length fieldINT16
Maximum length32,767 bytes
Null indicator-1

Wire Format:

NULLABLE_STRING => length:INT16 [data:BYTES[length]]
If length == -1: null (no data bytes)
If length >= 0: exactly 'length' data bytes follow

Encoding Example:

StringLengthEncoded Bytes (hex)
null-1FF FF
""000 00
"test"400 04 74 65 73 74

A variable-length prefixed UTF-8 string using compact encoding.

PropertyValue
Length fieldUNSIGNED_VARINT
Length semanticsActual length + 1
Maximum length2³²-2 bytes
Null handlingNot nullable

Wire Format:

COMPACT_STRING => length:UNSIGNED_VARINT data:BYTES[length-1]

The length field encodes actual_length + 1, so:

  • Length value 1 = empty string (0 bytes)
  • Length value 2 = 1-byte string
  • Length value N = (N-1)-byte string

Encoding Example:

StringWire LengthEncoded Bytes (hex)
""101
"a"202 61
"hello"606 68 65 6C 6C 6F

Null Constraint

A length value of 0 must be rejected as invalid for non-nullable COMPACT_STRING.

A variable-length prefixed UTF-8 string using compact encoding that may be null.

PropertyValue
Length fieldUNSIGNED_VARINT
Null indicator0
Maximum length2³²-2 bytes

Wire Format:

COMPACT_NULLABLE_STRING => length:UNSIGNED_VARINT [data:BYTES[length-1]]
If length == 0: null (no data bytes)
If length > 0: exactly 'length-1' data bytes follow

Encoding Example:

StringWire LengthEncoded Bytes (hex)
null000
""101
"test"505 74 65 73 74

A length-prefixed byte array that cannot be null.

PropertyValue
Length fieldINT32
Maximum length2,147,483,647 bytes
Null handlingNot nullable

Wire Format:

BYTES => length:INT32 data:BYTE[length]

A length-prefixed byte array that may be null.

PropertyValue
Length fieldINT32
Maximum length2,147,483,647 bytes
Null indicator-1

Wire Format:

NULLABLE_BYTES => length:INT32 [data:BYTE[length]]
If length == -1: null (no data bytes)
If length >= 0: exactly 'length' data bytes follow

A variable-length prefixed byte array using compact encoding.

PropertyValue
Length fieldUNSIGNED_VARINT
Length semanticsActual length + 1
Maximum length2³²-2 bytes
Null handlingNot nullable

Wire Format:

COMPACT_BYTES => length:UNSIGNED_VARINT data:BYTE[length-1]

Null Constraint

A length value of 0 must be rejected as invalid for non-nullable COMPACT_BYTES.

A variable-length prefixed byte array using compact encoding that may be null.

PropertyValue
Length fieldUNSIGNED_VARINT
Null indicator0
Maximum length2³²-2 bytes

Wire Format:

COMPACT_NULLABLE_BYTES => length:UNSIGNED_VARINT [data:BYTE[length-1]]
If length == 0: null (no data bytes)
If length > 0: exactly 'length-1' data bytes follow

A count-prefixed array of elements that may be null.

PropertyValue
Count fieldINT32
Maximum elements2,147,483,647
Null indicator-1

Wire Format:

ARRAY<T> => count:INT32 [elements:T[count]]
If count == -1: null array (no elements)
If count >= 0: exactly 'count' elements follow

Empty vs Null

An empty array (count = 0) is semantically distinct from a null array (count = -1). Implementations must preserve this distinction.

A variable-length count-prefixed array using compact encoding.

PropertyValue
Count fieldUNSIGNED_VARINT
Count semanticsActual count + 1
Null indicator0

Wire Format:

COMPACT_ARRAY<T> => count:UNSIGNED_VARINT [elements:T[count-1]]
If count == 0: null array (no elements)
If count > 0: exactly 'count-1' elements follow

Count Semantics:

Wire CountMeaning
0Null array
1Empty array (0 elements)
2Array with 1 element
NArray with N-1 elements

Message batch data in Kafka record format.

PropertyValue
Length fieldINT32
Null indicator-1
ContentOne or more RecordBatch structures

Wire Format:

RECORDS => length:INT32 [data:BYTE[length]]
If length == -1: null (no record data)
If length >= 0: exactly 'length' bytes of record batch data

Message batch data using compact encoding.

PropertyValue
Length fieldUNSIGNED_VARINT
Null indicator0
ContentOne or more RecordBatch structures

Wire Format:

COMPACT_RECORDS => length:UNSIGNED_VARINT [data:BYTE[length-1]]
If length == 0: null (no record data)
If length > 0: exactly 'length-1' bytes of record batch data

See Protocol Records for the record batch format specification.


Introduced in Kafka 2.4 (KIP-482), tagged fields enable forward-compatible protocol evolution without incrementing API versions.

TaggedFields => num_fields:UNSIGNED_VARINT [field:TaggedField]*
TaggedField => tag:UNSIGNED_VARINT size:UNSIGNED_VARINT data:BYTES[size]
FieldTypeDescription
num_fieldsUNSIGNED_VARINTNumber of tagged fields
tagUNSIGNED_VARINTUnique field identifier
sizeUNSIGNED_VARINTSize of field data in bytes
dataBYTESRaw field data
RequirementLevelDescription
Tag orderingmustTagged fields must be serialized in strictly ascending tag order
Unknown tagsmustImplementations must ignore (skip) unknown tagged fields
Duplicate tagsmustImplementations must reject duplicate tags as a protocol error
Tag value rangemustTag values must be non-negative

Tagged fields are only valid in "flexible" API versions:

API Version TypeRequest Tagged FieldsResponse Tagged Fields
Non-flexible
Flexible

Flexible Version Detection

Each API specifies which versions are "flexible" in its schema. Flexible versions use compact encodings (COMPACT_STRING, COMPACT_ARRAY, etc.) and include tagged field sections.


TypeSizeNullableCompact Variant
INT81-
INT162-
INT324-
INT648-
UINT162-
UINT324-
VARINT1-5-
VARLONG1-10-
UNSIGNED_VARINT1-5-
FLOAT648-
UUID16-
BOOLEAN1-
TypeLength FieldNullableCompact Variant
STRINGINT16COMPACT_STRING
NULLABLE_STRINGINT16COMPACT_NULLABLE_STRING
BYTESINT32COMPACT_BYTES
NULLABLE_BYTESINT32COMPACT_NULLABLE_BYTES
ARRAYINT32COMPACT_ARRAY
RECORDSINT32COMPACT_RECORDS

All multi-byte primitive types use big-endian (network) byte order. This applies to:

  • Fixed-width integers (INT16, INT32, INT64, UINT16, UINT32)
  • Floating point (FLOAT64)
  • UUID

Variable-length integers (VARINT, VARLONG, UNSIGNED_VARINT) use little-endian data bit ordering within their variable-length encoding.

All string types use UTF-8 encoding. Implementations must:

  • Encode strings as valid UTF-8
  • Accept and preserve valid UTF-8 sequences
  • Handle invalid UTF-8 as implementation-defined (may reject or replace)
ConcernRecommendation
Maximum message sizeValidate against configured limits before allocation
Array allocationCheck count bounds before allocating arrays
String lengthValidate length does not exceed available bytes