AlgoMaster Logo

Consumer Group States

Low Priority13 min readUpdated September 13, 2026
Listen to this chapter
Unlock Audio

A consumer group can report Stable while falling further behind its topic. Another group can report Empty while still holding the offsets it needs for a restart. These names describe the group’s coordination status, so reading them as application health signals can lead to the wrong diagnosis.

In this chapter, we’ll follow a group through its lifecycle, explain the states the classic and newer consumer protocols use, and connect those states to practical troubleshooting.

We’ll use a KRaft-based Kafka 4.3 cluster and the Apache Kafka Java consumer with automatic assignment through subscribe(). Our order-reporting group reads four partitions of orders.placed. We’ll examine each protocol separately, assuming no protocol migration during the examples.

1. What a Group State Describes

The group coordinator maintains the membership and assignment information for a consumer group. Its group state summarizes where that coordination currently stands: whether the group has members, is establishing an assignment, or has settled on one.

That is a different question from whether the application is processing records successfully. The coordinator does not inspect the reporting database to decide whether the group is stable. It also does not require the consumers to reach the end of the topic before reporting Stable.

Suppose A owns partitions 0 and 1, and B owns 2 and 3. Both consumers can have settled assignments while a slow database causes their backlog to grow. The coordination state can remain Stable throughout.

The opposite is possible too. A group can briefly leave Stable during a deployment even though every consumer is functioning correctly. A new member requires an assignment update, and the state reflects that work.

The vocabulary depends on the group protocol. Classic groups use PreparingRebalance and CompletingRebalance for their rebalance phases. Groups using the consumer protocol expose Assigning and Reconciling in their native state model. Both use Empty and Stable.

Kafka tools typically display names such as PreparingRebalance; Java enum constants use names such as PREPARING_REBALANCE. These are representations of the same state, not separate phases. Tool versions and compatibility APIs can affect what the tool displays, so interpret a state alongside the group type and client configuration.

2. The Classic Group Lifecycle

With group.protocol=classic, the coordinator brings members together for a membership round, then receives the assignment from a selected consumer leader. The states separate these two parts of the process.

Empty

Empty means the coordinator has no members in the group. This can happen before the first consumer joins or after the last member leaves or expires.

For order-reporting, imagine you stop both application instances overnight. Once Kafka removes their memberships, the group becomes empty. The topic can continue receiving records, and the group can retain its committed offsets.

When A starts and joins, the group begins establishing a membership round. It moves into PreparingRebalance.

PreparingRebalance

In PreparingRebalance, the coordinator is collecting the members that will participate in the next generation. A generation is a version of the classic group’s membership and assignment.

Consumers send JoinGroup requests. The coordinator waits for the required joins or the applicable timeout, rather than immediately calculating an assignment for whichever consumer arrived first. It can then continue with the members that remain eligible to participate.

For example, if B joins while A is already consuming, A must learn that the membership round is changing and rejoin. A slow response from A can keep this phase open longer. The state alone does not identify why A is slow; client logs and timing provide that evidence.

If no members remain, the group can return to Empty instead of completing a new assignment.

CompletingRebalance

Once the membership round is ready, the group enters CompletingRebalance. The coordinator has selected the participating members and a consumer group leader, but it is waiting for the group leader to submit the assignment and for the coordinator to save it.

The selected leader runs the assignor, the component that divides eligible partitions among members, and submits the result through SyncGroup. Other members also use SyncGroup to obtain their assignments.

The coordinator completes the assignment step, including saving the assignment, and moves the group to Stable. This does not mean every application has finished its assignment callback or processed its first record. It means the coordinator has established the assignment for that generation.

If a member disappears or the membership changes again before completion, the group may return to PreparingRebalance. Rebalancing is not a one-way sequence that must always finish on the first attempt.

Stable

In Stable, the classic group has an established assignment for its current generation. Members can maintain their sessions and use that assignment for consumption. Requests must still satisfy membership and other validation rules.

A new member, an eligible subscription change, or a detected member failure can start another membership round. The diagram shows common lifecycle paths. It omits internal cleanup and some retry paths to keep the coordination cycle readable.

The two rebalance states identify different waiting points. PreparingRebalance concerns assembling membership; CompletingRebalance concerns establishing the assignment for that membership.

These names do not tell you whether the assignor uses eager or cooperative partition revocation. Both approaches can use the classic state model. How much processing a change interrupts depends on the protocol behavior, assignor, and application callbacks, not just the state’s name.

3. States in the Consumer Protocol

With group.protocol=consumer, the coordinator computes a target assignment using a server-side assignor. Members then reconcile their current assignments with that target through their heartbeat exchanges.

Reconciliation means bringing each member’s actual partition ownership into agreement with the coordinator’s intended assignment. Computing the destination and completing the transfer are separate steps.

Assigning

An epoch is a version number. The group epoch tracks changes that require a new assignment, while the assignment epoch identifies the version the coordinator used to compute the target assignment.

For a nonempty group, Assigning means the group epoch is ahead of the assignment epoch. The target assignment has not yet caught up with the current group version.

This is a state definition, not proof that a background assignment calculation is running. With Kafka’s server-side assignors, the coordinator computes the target as part of handling the change. The intermediate state may not be visible in normal administrative snapshots. Do not expect to observe Assigning during every rebalance.

Reconciling

Once the target assignment is current, the group is Reconciling if members have not all reconciled to it. The coordinator knows the intended result, but the ownership changes have not all finished.

Suppose A owns partitions 0 and 1, while B owns 2 and 3. C joins, and the new target moves partition 1 from A to C. This is one illustrative assignment, not a promise about a particular assignor’s choice.

A must release partition 1 before C can take it over through the protocol. Until the required handoff and member updates complete, the group can remain Reconciling. Meanwhile, A can retain partition 0, and B can retain 2 and 3. Unaffected partitions need not wait for every member to finish reconciling, though application processing may still pause for other reasons.

Stable

The consumer group becomes Stable when its target assignment is current and all members have reconciled to it. As with the classic protocol, this says nothing about consumer lag or completed database updates.

The diagram shows the logical stages for a nonempty group. The dashed path represents an intermediate assignment stage that administrative polling may never observe. It is not a required sequence of visible snapshots.

Further membership changes can introduce another target before reconciliation finishes. The group does not have to visit Stable between changes. If the coordinator removes all members, the group becomes Empty.

The useful distinction is whether the target itself is behind or whether members are still catching up to a current target. Treating both as simply “rebalancing” loses information that can help locate a delay.

4. Empty, Dead, and Unknown

Some state names describe absence or lifecycle boundaries. They need more care than a simple healthy-or-unhealthy interpretation.

Empty and Retained Progress

Empty describes membership, not topic contents or checkpoint deletion. If order-reporting last committed 130 for partition 0, that checkpoint can remain after the group becomes empty.

A returning consumer can normally resume at 130 if the checkpoint and required records remain available. Offset expiration, topic retention, and the application’s reset or seek behavior affect recovery independently of the group state.

Our examples use automatic group assignment. There is a relevant exception when inspecting other applications: a consumer using manual assign() can store offsets under a group ID without joining automatic membership management. Such an offset-only group can appear Empty even while that application reads records. Check how the consumer assigns partitions before concluding that no application is running.

Dead and Missing Groups

Dead means the coordinator is retiring its local representation of the group, for example during deletion or cleanup. Classic coordinator internals can also retire their local group object when ownership moves to another broker. In that case, the durable group may continue under the new coordinator.

It does not mean that one consumer process crashed. A consumer crash normally leads to member removal and, if members remain, an assignment update.

Nor should you expect a deleted group to remain visible with a Dead label. Kafka 4.3’s Admin API reports a missing group with GroupIdNotFoundException; older versions could return a description in the Dead state. Monitoring software must account for this distinction instead of assuming every missing group has an observable terminal state.

Unknown and Request Errors

Unknown is an API representation for a state the client cannot interpret, for example when a newer broker returns a name an older client does not recognize. It is not a normal phase between joining and consuming.

A failed describe request is different again. COORDINATOR_LOAD_IN_PROGRESS means the coordinator is loading state; it is not the consumer group’s state. Connection, authorization, and coordinator errors can prevent a tool from obtaining a state at all.

Keep these outcomes separate: an observed group state, an absent group, and a failed observation each call for different investigation.

5. Inspecting a Running Group

Use Kafka 4.3’s command-line tools from a Kafka installation to inspect an existing group. These read-only examples assume a local plaintext broker at localhost:9092 and a group named order-reporting. They do not create the group or change its offsets.

Start with its coordination state:

The output includes the coordinator, state, and member count. Read the state alongside the members the coordinator currently recognizes. An application process can have exited before its membership timeout expires, so that count is not necessarily a count of healthy processes.

To inspect the members and their partition assignments, run:

Then inspect the group’s saved progress:

For a secured cluster, use its broker addresses and add --command-config with an appropriate client properties file. The account running the command needs permission to inspect the group.

These commands provide separate observations, not one atomic snapshot. Membership can change between them. Fast transitions may also finish between samples, so a group that repeatedly reports Stable in occasional checks may still experience brief rebalances.

Use timestamps and client or coordinator logs to reconstruct a sequence. Confirm the deployed group protocol before interpreting its transition names, especially if a monitoring tool uses an older administrative API.

6. Interpreting State Patterns

A single state tells you where coordination stands at one moment. Its duration, recurrence, and relationship to processing progress tell you whether it deserves attention.

Repeated Classic Rebalance Cycles

Suppose a deployment adds C to order-reporting. A brief transition through PreparingRebalance and CompletingRebalance, followed by Stable, is a normal part of updating the group.

Now suppose C repeatedly starts, joins, and crashes. The group can repeatedly begin new membership rounds, interrupting progress even though it occasionally reaches Stable. Compare transition times with process restarts, member IDs, and membership errors. The recurring change matters more than any one snapshot.

If PreparingRebalance lasts unusually long for this application, inspect which members are failing to rejoin promptly and whether changes keep extending or restarting the round. If CompletingRebalance persists, inspect the selected leader’s assignment work, synchronization requests, and coordinator errors. Neither state alone proves that a timeout setting is wrong.

Prolonged Reconciliation

In the A-to-C transfer of partition 1, a slow revocation callback in A can delay the handoff. The group may remain Reconciling while B continues processing its partitions normally.

Inspect the members whose current and target assignments differ, along with their heartbeat exchanges and callback timing. The group-wide label identifies unfinished coordination; member-level evidence identifies which transfer is waiting.

Restarting every consumer based only on this label can introduce more membership changes. First establish whether the group is making progress toward the target or repeatedly receiving a new one.

Stable with Growing Lag

Assume partition 0 has a log end offset of 200 and a group committed offset of 130. The reported committed-offset lag is 70 offset positions. The group can be Stable throughout this backlog.

That lag may reflect slow processing, infrequent commits, or stalled progress. It is not by itself a count of unfinished database operations; compacted or transactional logs can also contain gaps in visible record offsets.

Compare processing rate, commit activity, and downstream latency. If A processed through offset 139 but still has 130 committed, a failure can cause those processed records to return again. Becoming Stable after recovery does not close that gap or guarantee duplicate-free business effects.

Unexpectedly Empty

For a service expected to run continuously with automatic assignment, Empty is a reason to investigate missing membership. Check whether the instances stopped, failed to join, connected to the wrong cluster, or started with a different group ID.

For a scheduled reporting job that intentionally exits between runs, the same state may be expected. Judge the state by when the application should be running; the same state can be normal for one application and a problem for another.

Summary

Group states describe membership and assignment coordination. Classic groups establish membership in PreparingRebalance and assignments in CompletingRebalance. The consumer protocol distinguishes a target assignment that is behind in Assigning from members still approaching that target in Reconciling.

Stable does not prove processing health, and Empty does not imply that saved offsets are gone. Interpret states alongside the protocol, member assignments, progress, and the sequence of changes over time. Missing groups and failed state requests provide different evidence and you should investigate them separately.