KIP-394 — require member ID for initial join
Status: partial — see the KIP index.
What's missing
The v4+ two-step join handshake. kaas defines the
MEMBER_ID_REQUIRED error code (79, crates/kaas-coordinator/src/group.rs)
but never returns it: join() takes the legacy assign-inline path for all
versions — a first-time joiner is admitted directly instead of being
bounced with a broker-assigned member ID and re-joining with it. The
follow-up marker sits in the join path
(crates/kaas-coordinator/src/group.rs, the pending-member registry
comment).
What the KIP changes in Apache Kafka
Before KIP-394, a JoinGroup that timed out client-side could leave a ghost
member in the group: the broker had created a member ID the client never
learned. From JoinGroup v4, an initial join with an empty member ID is
answered MEMBER_ID_REQUIRED plus a broker-assigned member ID; the
client immediately re-joins with that ID. Ghosts stop accumulating because
only joins that echo a known ID create members.
What kaas has, and why the gap is tolerable so far
kaas serves JoinGroup v2–v9 (matrix) with the pre-KIP-394 admission flow at every version. The ghost-member problem the KIP fixes is bounded by two kaas behaviours: session-timeout eviction reaps members whose clients vanished, and the rebalance sweep evicts non-rejoining dynamic members (see KIP-345 for the static-member exception). Clients negotiate and operate correctly — the Java client only sends the empty member ID on first join and handles either reply shape — but the tracked follow-up is to implement the real two-step handshake rather than rely on timeouts.
See JoinGroup for the full join flow.
How the partial state is verified
Join/rebalance behaviour is covered by group-coordinator unit tests and
scripts/kafka-consumer-groups.sh / scripts/kafka-verifiable-consumer.sh
end-to-end runs. The gap is explicit in source — grep
MEMBER_ID_REQUIRED in crates/kaas-coordinator/src/group.rs.