Skip to content

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

Kafka Consumer Group Protocol APIs

This document specifies the Kafka protocol APIs used for consumer group management, coordination, and offset tracking. These APIs implement the consumer group protocol that enables dynamic partition assignment and coordinated consumption.


API KeyNamePurpose
8OffsetCommitCommit consumer offsets
9OffsetFetchRetrieve committed offsets
10FindCoordinatorLocate group coordinator
11JoinGroupJoin or create consumer group
12HeartbeatMaintain group membership
13LeaveGroupLeave consumer group
14SyncGroupSynchronize partition assignments
15DescribeGroupsDescribe group state
16ListGroupsList all groups
42DeleteGroupsDelete consumer groups
47OffsetDeleteDelete committed offsets

Consumer group membership protocol from coordinator discovery to leaveConsumerCoordinatorConsumerConsumerCoordinatorCoordinatorFind CoordinatorFindCoordinatorRequest(group_id)FindCoordinatorResponse(coordinator)Join GroupJoinGroupRequest(group_id, protocols)All members send JoinGroupJoinGroupResponse(generation_id, leader, members)Sync GroupSyncGroupRequest(assignments)Only leader sends assignmentsSyncGroupResponse(assignment)Steady Stateloop[while member of group]HeartbeatRequestHeartbeatResponseLeave GroupLeaveGroupRequestLeaveGroupResponse

The FindCoordinator API locates the broker serving as coordinator for a consumer group, transaction, or share group.

VersionKafkaKey Changes
00.8.2Initial version (group only)
10.10.0Throttle time
20.11.0Key type (transaction support)
32.4.0Flexible versions
43.6.0Batched requests (KIP-699)
53.8.0TRANSACTION_ABORTABLE errors (KIP-890)
64.0.0Share groups (KIP-932)
FindCoordinatorRequest =>
key: STRING
key_type: INT8
coordinator_keys: [STRING]
FieldTypeDescription
keySTRINGCoordinator key (v0-3)
key_typeINT80=GROUP, 1=TRANSACTION, 2=SHARE
coordinator_keysARRAYMultiple keys (v4+)

For key_type=SHARE, the coordinator key format is groupId:topicId:partition.

FindCoordinatorResponse =>
throttle_time_ms: INT32
error_code: INT16
error_message: NULLABLE_STRING
node_id: INT32
host: STRING
port: INT32
coordinators: [Coordinator]
Coordinator =>
key: STRING
node_id: INT32
host: STRING
port: INT32
error_code: INT16
error_message: NULLABLE_STRING
FieldTypeDescription
node_idINT32Coordinator broker ID (v0-3)
hostSTRINGCoordinator hostname (v0-3)
portINT32Coordinator port (v0-3)

The coordinator is deterministically selected based on the coordinator key and internal topic:

partition = abs(hash(key)) % internal_topic.partitions
coordinator = leader(internal_topic, partition)

Key types map to internal topics:

  • GROUP -> __consumer_offsets
  • TRANSACTION -> __transaction_state
  • SHARE -> __share_group_state
AspectGuarantee
DeterminismSame group ID always maps to same partition
ConsistencyCoordinator stable unless broker fails
FailoverOn coordinator failure, new leader elected
Error CodeRetriableCauseRecovery
COORDINATOR_NOT_AVAILABLECoordinator initializingWait, retry
NOT_COORDINATORCoordinator movedRetry FindCoordinator
GROUP_AUTHORIZATION_FAILEDNo Describe permissionCheck ACLs

The JoinGroup API joins a consumer to a group, triggering rebalancing if necessary. The coordinator selects a group leader.

VersionKafkaKey Changes
00.9.0Initial version
10.10.1Rebalance timeout
42.1.0Second join with assigned member ID
52.3.0Group instance ID
62.4.0Flexible versions
72.7.0Protocol type in response (KIP-559)
83.0.0Reason field (KIP-800)
93.5.0Skip assignment in response
JoinGroupRequest =>
group_id: STRING
session_timeout_ms: INT32
rebalance_timeout_ms: INT32
member_id: STRING
group_instance_id: NULLABLE_STRING
protocol_type: STRING
protocols: [Protocol]
reason: NULLABLE_STRING
Protocol =>
name: STRING
metadata: BYTES
FieldTypeDescription
group_idSTRINGConsumer group identifier
session_timeout_msINT32Session timeout for heartbeats
rebalance_timeout_msINT32Maximum time to join
member_idSTRINGMember ID (empty for new members)
group_instance_idNULLABLE_STRINGStatic membership ID
protocol_typeSTRINGProtocol type (e.g., “consumer”)
protocolsARRAYSupported assignment protocols
JoinGroupResponse =>
throttle_time_ms: INT32
error_code: INT16
generation_id: INT32
protocol_type: NULLABLE_STRING
protocol_name: NULLABLE_STRING
leader: STRING
skip_assignment: BOOLEAN
member_id: STRING
members: [Member]
Member =>
member_id: STRING
group_instance_id: NULLABLE_STRING
metadata: BYTES
FieldTypeDescription
generation_idINT32Group generation (increments per rebalance)
protocol_nameNULLABLE_STRINGSelected assignment protocol
leaderSTRINGGroup leader member ID
member_idSTRINGAssigned member ID
membersARRAYMember list (leader only)
Rebalance with a leader and a follower consumer joining and syncingConsumer AConsumer BCoordinatorConsumer AConsumer AConsumer BConsumer BCoordinatorCoordinatorInitial JoinJoinGroup(member_id="")Wait for rebalance_timeoutJoinGroup(member_id="")JoinResponse(leader=A, members=[A,B])JoinResponse(leader=A, members=[])A is leader, receives member listB is follower, empty membersSyncSyncGroup(assignments)SyncGroup(empty)SyncResponse(assignment for A)SyncResponse(assignment for B)
Consumer group coordinator state machineConsumer group coordinator state machineEmptyPreparingRebalanceCompletingRebalanceStableDeadPreparingRebalancegroup createdfirst member joinsall members joined(or timeout)all members syncedmember join/leave/heartbeat failall members leavegroup deleted
AspectGuarantee
Leader electionCoordinator selects leader (often the first to join)
Generation IDIncrements on each successful rebalance
Member IDAssigned by coordinator, must be used in subsequent requests
TimeoutMembers not completing join within rebalance_timeout are removed

With group.instance.id:

BehaviorStatic Membership
Rejoin after restartPreserves member ID
Session timeoutLonger grace period
Rebalance avoidanceNo rebalance on transient failures

The Heartbeat API maintains consumer group membership and detects failures.

VersionKafkaKey Changes
00.9.0Initial version
10.10.1Throttle time
20.11.0Response before throttling
32.3.0Group instance ID
42.4.0Flexible versions
HeartbeatRequest =>
group_id: STRING
generation_id: INT32
member_id: STRING
group_instance_id: NULLABLE_STRING
FieldTypeDescription
group_idSTRINGConsumer group ID
generation_idINT32Current group generation
member_idSTRINGMember’s assigned ID
group_instance_idNULLABLE_STRINGStatic membership ID
HeartbeatResponse =>
throttle_time_ms: INT32
error_code: INT16
AspectGuarantee
FrequencyMust send within session.timeout.ms
Failure detectionMissing heartbeats trigger rebalance
Rebalance signalREBALANCE_IN_PROGRESS indicates pending rebalance
Error CodeMeaningRecovery
NONESuccessContinue heartbeating
REBALANCE_IN_PROGRESSRebalance startedRejoin group
ILLEGAL_GENERATIONStale generationRejoin group
UNKNOWN_MEMBER_IDMember removedRejoin group
FENCED_INSTANCE_IDStatic member fencedExit or rejoin

The SyncGroup API distributes partition assignments after a successful rebalance.

VersionKafkaKey Changes
00.9.0Initial version
10.10.1Throttle time
20.11.0Response improvements
32.3.0Group instance ID
42.4.0Flexible versions
52.7.0Protocol type/name
SyncGroupRequest =>
group_id: STRING
generation_id: INT32
member_id: STRING
group_instance_id: NULLABLE_STRING
protocol_type: NULLABLE_STRING
protocol_name: NULLABLE_STRING
assignments: [Assignment]
Assignment =>
member_id: STRING
assignment: BYTES
FieldTypeDescription
assignmentsARRAYPartition assignments (leader only)
SyncGroupResponse =>
throttle_time_ms: INT32
error_code: INT16
protocol_type: NULLABLE_STRING
protocol_name: NULLABLE_STRING
assignment: BYTES
FieldTypeDescription
assignmentBYTESMember’s partition assignment

The assignment bytes follow a protocol-specific format. For the “consumer” protocol:

ConsumerProtocolAssignment =>
assigned_partitions: [TopicPartition]
user_data: BYTES
TopicPartition =>
topic: STRING
partitions: [INT32]
AspectGuarantee
Leader responsibilityOnly leader must include assignments
Follower behaviorNon-leaders must send empty assignments
AtomicityAll members receive assignments when coordinator responds
ConsistencySame assignment for same generation

The LeaveGroup API gracefully removes members from a consumer group.

VersionKafkaKey Changes
00.9.0Initial version
10.10.1Throttle time
20.11.0Response before throttling
32.3.0Batch member removal + group instance ID
42.4.0Flexible versions
53.0.0Reason field (KIP-800)
LeaveGroupRequest =>
group_id: STRING
member_id: STRING
members: [MemberIdentity]
MemberIdentity =>
member_id: STRING
group_instance_id: NULLABLE_STRING
reason: NULLABLE_STRING
LeaveGroupResponse =>
throttle_time_ms: INT32
error_code: INT16
members: [MemberResponse]
MemberResponse =>
member_id: STRING
group_instance_id: NULLABLE_STRING
error_code: INT16
AspectGuarantee
Immediate effectMember removed immediately
Rebalance triggerRemaining members notified via heartbeat
Static membersMay leave without triggering immediate rebalance

The OffsetCommit API stores consumer offsets in the __consumer_offsets topic.

VersionKafkaKey Changes
00.8.1Initial version (removed in 4.0)
10.8.2Commit timestamp (removed in 4.0)
20.9.0Retention time (4.0 baseline)
30.11.0Throttle time
52.1.0Retention time removed
62.1.0Leader epoch
72.3.0Group instance ID
82.4.0Flexible versions
93.5.0Consumer group protocol (KIP-848)
104.0.0Topic IDs
OffsetCommitRequest =>
group_id: STRING
generation_id_or_member_epoch: INT32
member_id: STRING
group_instance_id: NULLABLE_STRING
topics: [Topic]
Topic =>
name: STRING
topic_id: UUID
partitions: [Partition]
Partition =>
partition_index: INT32
committed_offset: INT64
committed_leader_epoch: INT32
committed_metadata: NULLABLE_STRING

Topic names are used through v9; v10+ uses topic_id instead.

FieldTypeDescription
generation_id_or_member_epochINT32Group generation (classic) or member epoch (consumer protocol)
committed_offsetINT64Offset to commit
committed_leader_epochINT32Leader epoch of committed offset
committed_metadataNULLABLE_STRINGApplication metadata
OffsetCommitResponse =>
throttle_time_ms: INT32
topics: [Topic]
Topic =>
name: STRING
topic_id: UUID
partitions: [Partition]
Partition =>
partition_index: INT32
error_code: INT16
AspectGuarantee
DurabilityCommitted to replicated __consumer_offsets topic
VisibilityAvailable immediately after successful commit
Generation checkMust match current generation (if group member)
RetentionSubject to offsets.retention.minutes
Error CodeRetriableCauseRecovery
ILLEGAL_GENERATIONStale generationRejoin group
UNKNOWN_MEMBER_IDNot a group memberRejoin group
OFFSET_METADATA_TOO_LARGEMetadata too largeReduce metadata
GROUP_AUTHORIZATION_FAILEDNo Read permissionCheck ACLs

The OffsetFetch API retrieves committed offsets for a consumer group.

VersionKafkaKey Changes
00.8.1Initial version (removed in 4.0)
10.8.2Kafka-stored offsets (4.0 baseline)
20.10.2All partitions + top-level error
30.11.0Throttle time
52.1.0Leader epoch
62.4.0Flexible versions
72.5.0Require stable
83.0.0Multiple groups
93.5.0Consumer group protocol (KIP-848)
104.0.0Topic IDs
OffsetFetchRequest =>
group_id: STRING
topics: [Topic]
groups: [Group]
require_stable: BOOLEAN
Topic =>
name: STRING
partition_indexes: [INT32]
Group =>
group_id: STRING
member_id: NULLABLE_STRING
member_epoch: INT32
topics: [Topic]
FieldTypeDescription
topicsARRAYTopics/partitions to fetch (null for all)
require_stableBOOLEANIf true, unstable offsets return a retriable error
OffsetFetchResponse =>
throttle_time_ms: INT32
topics: [Topic]
error_code: INT16
groups: [Group]
Topic =>
name: STRING
partitions: [Partition]
Partition =>
partition_index: INT32
committed_offset: INT64
committed_leader_epoch: INT32
metadata: NULLABLE_STRING
error_code: INT16
FieldTypeDescription
committed_offsetINT64Last committed offset (-1 if none)
committed_leader_epochINT32Leader epoch of committed offset
metadataNULLABLE_STRINGApplication metadata
AspectGuarantee
ConsistencyReturns latest committed offset
No offsetReturns -1 if no offset committed
require_stableWith true, waits for pending transactions

The DescribeGroups API retrieves detailed information about consumer groups.

VersionKafkaKey Changes
00.9.0Initial version
10.10.1Throttle time
20.11.0Response improvements
32.3.0Authorized operations
42.4.0KIP-345
52.4.0Flexible versions
63.9.0GROUP_ID_NOT_FOUND (KIP-1043)
DescribeGroupsRequest =>
groups: [STRING]
include_authorized_operations: BOOLEAN
DescribeGroupsResponse =>
throttle_time_ms: INT32
groups: [Group]
Group =>
error_code: INT16
group_id: STRING
group_state: STRING
protocol_type: STRING
protocol_data: STRING
members: [Member]
authorized_operations: INT32
Member =>
member_id: STRING
group_instance_id: NULLABLE_STRING
client_id: STRING
client_host: STRING
member_metadata: BYTES
member_assignment: BYTES
FieldTypeDescription
group_stateSTRINGCurrent group state
protocol_typeSTRINGProtocol type (e.g., “consumer”)
protocol_dataSTRINGSelected protocol name
member_assignmentBYTESCurrent partition assignment
StateDescription
EmptyNo active members
PreparingRebalanceRebalance in progress
CompletingRebalanceWaiting for SyncGroup
StableActive and stable
DeadGroup being deleted

The ListGroups API lists all consumer groups on a broker.

VersionKafkaKey Changes
00.9.0Initial version
10.10.1Throttle time
32.4.0Flexible versions
42.6.0States filter (KIP-518)
53.5.0Types filter (KIP-848)
ListGroupsRequest =>
states_filter: [STRING]
types_filter: [STRING]
FieldTypeDescription
states_filterARRAYFilter by group states
types_filterARRAYFilter by group types
ListGroupsResponse =>
throttle_time_ms: INT32
error_code: INT16
groups: [Group]
Group =>
group_id: STRING
protocol_type: STRING
group_state: STRING
group_type: STRING

The DeleteGroups API deletes consumer groups.

VersionKafkaKey Changes
01.1.0Initial version
12.0.0Response improvements
22.4.0Flexible versions
DeleteGroupsRequest =>
groups_names: [STRING]
DeleteGroupsResponse =>
throttle_time_ms: INT32
results: [Result]
Result =>
group_id: STRING
error_code: INT16
AspectGuarantee
PreconditionGroup must be Empty or Dead
AtomicityEach group deletion is independent
EffectRemoves group and all committed offsets

The OffsetDelete API deletes committed offsets for a group and set of partitions.

VersionKafkaKey Changes
00.11.0Initial version
OffsetDeleteRequest =>
group_id: STRING
topics: [Topic]
Topic =>
name: STRING
partitions: [Partition]
Partition =>
partition_index: INT32
OffsetDeleteResponse =>
error_code: INT16
throttle_time_ms: INT32
topics: [Topic]
Topic =>
name: STRING
partitions: [Partition]
Partition =>
partition_index: INT32
error_code: INT16

Complete consumer flow from startup through the consume loopApplicationConsumerAny BrokerCoordinatorPartition LeaderApplicationApplicationConsumerConsumerAny BrokerAny BrokerCoordinatorCoordinatorPartition LeaderPartition LeaderStartupnew KafkaConsumer()MetadataRequestMetadataResponseFindCoordinatorRequest(group_id)FindCoordinatorResponse(coordinator)Join GroupJoinGroupRequestJoinGroupResponse(generation, leader)SyncGroupRequestSyncGroupResponse(assignment)Fetch OffsetsOffsetFetchRequestOffsetFetchResponse(offsets)Consume Looploop[poll()]Heartbeat (in parallel)HeartbeatRequestHeartbeatResponseFetch (in parallel)FetchRequestFetchResponse(records)OffsetCommitRequestOffsetCommitResponseShutdownLeaveGroupRequestLeaveGroupResponse