A consumer can reach the broker storing its records and still fail to join its group or commit an offset. Those operations depend on another role in the cluster: the group coordinator.
The coordinator gives group members a common place to manage membership and save progress. Understanding where it runs, how it stores state, and how clients recover when it moves helps explain failures that otherwise look like unrelated consumer errors.
We’ll follow the order-reporting group in a KRaft-based Kafka 4.3 cluster. Its consumers use the Apache Kafka Java client, subscribe to orders.placed, and commit offsets to Kafka. The offset examples use ordinary, non-transactional commits.
Suppose consumers A and B share the work of reading four partitions of orders.placed. They need a consistent view of who belongs to the group, which assignments are current, and which offsets the group has saved.
One broker acts as the group coordinator for order-reporting. It handles membership requests, tracks consumer liveness, participates in assignment changes, and serves offset commit and offset lookup requests. All members of this group use the same coordinator while that broker holds the role.
The coordinator runs inside a Kafka broker. You do not deploy a separate coordinator service or configure consumers with a permanent coordinator address. A broker can coordinate many groups while also storing ordinary topic partitions.
Several Kafka roles involve leadership, but they have different responsibilities:
For example, Broker 1 might serve records from orders.placed partition 0, while Broker 3 coordinates order-reporting. Consumer A reads order records from Broker 1 and commits its progress through Broker 3.
The coordinator does not inspect the order’s JSON value, apply the reporting update, or approve each record before A reads it. Its job concerns the group’s coordination and checkpoints. The application remains responsible for completing business work safely.
Kafka chooses a group’s coordinator based on where it stores the group’s state. That state lives in a partitioned internal topic named __consumer_offsets.
The broker hashes the group ID and maps it to one partition of this internal topic. The leader of that partition is the group’s coordinator. The mapping depends on the group ID and the internal topic’s partition count, not on which application topics the group subscribes to.
Suppose order-reporting maps to internal partition 7, which Broker 3 currently leads. This is an illustrative placement, not a calculated hash result. Broker 3 coordinates the group even if none of its consumers read order records from that broker.
A group subscribed to several topics still has one coordinator. Its committed offsets for all those topics belong to the same internal partition. Conversely, many unrelated groups can map to internal partition 7 and share Broker 3 as their coordinator.
Consumer A starts with bootstrap.servers and uses the cluster connection to send a FindCoordinator request for order-reporting. Any reachable Kafka broker can answer this discovery request when it has the necessary metadata. The response identifies the coordinator broker and its connection address.
The diagram separates finding the coordinator from using it. Broker 1 is the discovery contact in this example; it does not forward A’s subsequent group requests.
A caches this location and connects directly to Broker 3. It does not repeat discovery before every heartbeat or commit. If the location becomes invalid, the client can discover it again.
This explains why reaching a bootstrap address is only the first connectivity check. A must also reach the coordinator address Kafka returns. An incorrect advertised hostname or a network rule blocking Broker 3 can break group operations even though discovery through Broker 1 succeeds.
The group ID is therefore more than a display label. Changing it creates a different group identity with separate checkpoints and potentially a different coordinator. Renaming a group to escape a connection problem can also change where the application starts reading.
The coordinator needs fast access to current state, but that state must survive the broker process. Kafka uses memory for active request handling and the internal log for durable recovery.
The durable records include committed offsets and group metadata. The metadata representation depends on the protocol: classic groups persist their membership and assignment information differently from groups using the newer consumer protocol. Consumers do not need to understand those internal record formats.
For offsets, the logical key identifies a group, topic, and partition. For example, one entry may say that order-reporting should resume orders.placed partition 0 at offset 130. Another entry independently tracks partition 1.
Although Kafka calls both values offsets, the saved value 130 and the position of its storage record inside __consumer_offsets are different numbers. The first identifies a position in the order log. The second identifies where Kafka stored a checkpoint record in its internal log.
__consumer_offsets uses log compaction, which allows Kafka to remove older records for a key while retaining its latest value. Saving 140 for the same group, topic, and partition appends another checkpoint record; it does not update the old log entry in place. Cleanup happens later.
This lets the coordinator rebuild current checkpoints without keeping every historical commit forever. Offset expiration and deletion are separate concerns: a group’s stored offsets are not an unlimited archive of every position it has used.
The coordinator also maintains operational state such as timers and pending responses. Not every heartbeat produces a durable log entry. A heartbeat may simply maintain a member’s liveness, while a membership or assignment change requires persistent state updates.
In Kafka 4.3, the coordinator runtime processes operations for each internal partition one at a time. This keeps changes to the groups sharing that partition ordered. Different internal partitions provide separate units of coordinator work.
Memory makes those operations efficient. The replicated log makes the durable part recoverable. After taking over an internal partition, a new coordinator loads its records to reconstruct the state it needs before serving the affected groups normally.
The coordinator’s response depends on the request, the current group state, and the caller’s membership information. It cannot accept every request just because it arrived at the correct broker.
For automatically managed consumers, relevant requests carry a member identity and version information. Classic groups use a generation, which identifies a membership round. The consumer protocol uses epochs, version numbers that track changes to group and member state. The coordinator uses these fields to detect stale membership information and reject requests that fail the applicable checks.
In a classic group, the coordinator handles JoinGroup and SyncGroup, selects a consumer group leader, and distributes the assignment that this consumer computes. It also handles heartbeats and departures.
With the consumer protocol, members exchange ConsumerGroupHeartbeat requests with the coordinator. A server-side assignor computes the target assignment, and the coordinator manages each member’s progress toward it. It does not wait for a consumer leader to calculate the result.
In both cases, the coordinator manages the agreement about partition ownership. The protocol determines how that agreement changes; the coordinator remains the broker-side authority for the group.
Suppose A has finished processing all records through offset 129 in orders.placed partition 0. It sends an OffsetCommit request that saves 130 as the next restart position.
The coordinator checks the request, including relevant membership and offset metadata constraints. For a valid commit, it creates a checkpoint record and appends it to internal partition 7. The coordinator responds successfully only after replication commits the write. An in-memory update alone is not enough.
For this diagram, assume internal partition 7 has three replicas, all in sync: Broker 3 leads it, and Brokers 1 and 2 follow it. An in-sync replica is a replica Kafka considers sufficiently caught up with the leader. The followers obtain the record by fetching from the leader, and the coordinator responds only after that replication completes.
With all three replicas in sync in this example, the record reaches both followers before success. The actual durability and availability depend on the internal topic’s replication, minimum in-sync replica requirements, and the failures the cluster experiences. If the required write cannot complete in time, the commit can fail.
An OffsetFetch request serves a different purpose: it asks for the saved checkpoint. The coordinator answers from its recovered, committed state rather than scanning the order topic. It cannot infer the checkpoint by looking at how many records the consumer fetched.
The success response confirms the saved Kafka offset. It does not verify A’s claim that the database work through 129 finished. If the application committed prematurely, the coordinator can successfully store a checkpoint that skips unfinished work during recovery.
Now suppose Broker 3 fails. The consumers lose their coordinator connection, and internal partition 7 needs a new leader. The group ID and its mapping to partition 7 stay the same.
Assume the KRaft controller quorum is available and Broker 2 has an eligible replica. Kafka can elect Broker 2 as the new leader of partition 7. That leadership change also gives Broker 2 responsibility for the groups stored there, including order-reporting.
The diagram shows the recovery dependencies. State loading and client discovery can overlap, so discovering Broker 2 does not necessarily mean it is ready to handle every group request yet.
An old broker that no longer owns the internal partition must stop serving as its coordinator. A reachable broker can return NOT_COORDINATOR when a client sends it a group request using an outdated location. Clients then discover the coordinator again.
Other transient errors describe different points in recovery:
The Java client handles many transient retries internally, within its timeout limits. An application can still receive a failure when those limits expire or when its membership is no longer valid.
Coordinator movement does not inherently erase committed offsets or require every partition assignment to change. The outcome depends on the recovered group state, protocol, and how long communication stopped. If members expire or must rejoin, a rebalance may follow.
Suppose A sent the commit for 130 immediately before Broker 3 failed. There are two materially different outcomes. If Kafka committed the checkpoint but A never received the response, Broker 2 can recover 130. If Kafka never committed the write, the recovered checkpoint may still be the earlier value, such as 120.
From A’s timeout alone, the application cannot tell which happened. A later successful offset lookup can establish the stored checkpoint, but that checkpoint still says nothing about database updates that the application did not commit atomically with that checkpoint.
If a replacement consumer resumes from 120, it can read already processed records again. Safe recovery therefore still requires duplicate handling. A coordinator failover preserves recoverable Kafka state; it does not make an external side effect happen exactly once.
To inspect a running group, use the Kafka 4.3 command-line tools from a Kafka installation. The following read-only command assumes a local plaintext broker at localhost:9092 and an existing order-reporting group. This is a local inspection example, not a production security configuration.
The output includes the group’s coordinator, state, and member count. The coordinator shown is the broker currently responsible for this group, not necessarily the broker you specify with --bootstrap-server.
For a secured cluster, use its broker addresses and supply an appropriate client properties file through --command-config. The account running the command needs permission to inspect the group.
Once you know the coordinator, relate the symptom to its responsibility. Repeated discovery failures call for checking the returned broker address and the availability of the relevant internal partition. Prolonged loading errors call for checking coordinator recovery and broker storage health. Slow commits call for inspecting request latency and replication of __consumer_offsets, even when replication of orders.placed looks healthy.
Several groups failing together can be a useful clue. They may share a coordinator broker or even the same internal partition despite consuming different application topics. That shared dependency can explain why their failures start at the same time.
The same relationship affects capacity. Many members, frequent commits, and repeated membership changes all create coordinator work. Adding consumers to one group can increase that work, but it does not distribute that group across several coordinators. Brokers can share coordination across different internal partitions; one group remains tied to one of them.
Finally, coordinator availability and record availability are separate. Consumers may temporarily process buffered records, and some fetch activity may continue while coordination recovers. That does not mean the group can safely operate indefinitely without a coordinator. Membership maintenance and durable checkpoints still need it.
A group’s ID maps to a partition of __consumer_offsets, and that partition’s leader acts as its coordinator. Consumers discover this broker and use it for membership and offset operations while fetching application records separately.
The coordinator combines in-memory state with a replicated internal log. That allows another broker to recover the group after a leadership change, though discovery, state loading, and retries can interrupt requests. A successful commit confirms a Kafka checkpoint; a timeout can leave its outcome uncertain, and neither result proves that external business work completed correctly.