Summary
The ConsumerGroup implementation doesn't handle MemberIdRequired (error code 79) per KIP-394. When a broker returns this error with an assigned member ID in the response, the client should retry the JoinGroup request using that member ID. Instead, the current code treats it as a fatal error, discards the member ID, and retries with an empty string, creating an infinite failure loop.
Root cause
In consumergroup.go, the joinGroup method (line ~941) treats any non-zero error code as fatal:
if err == nil && response.ErrorCode != 0 {
err = Error(response.ErrorCode)
}
if err != nil {
return "", 0, nil, err // member ID from response is lost
}
The caller nextGeneration then hits the default case in the error switch, which clears the member ID and retries after a backoff:
default:
_ = cg.leaveGroup(memberID)
memberID = ""
backoff = time.After(cg.config.JoinGroupBackoff)
The member ID returned in the MemberIdRequired response is never preserved.
Expected behavior
Per KIP-394, when the broker returns MemberIdRequired:
- Extract the
MemberID from the JoinGroup response
- Retry the JoinGroup request with that member ID
- The second attempt should succeed
How to reproduce
Connect a ConsumerGroup to a Kafka-compatible broker that enforces KIP-394 (e.g., Tansu). The consumer group will fail to join and retry indefinitely with [79] Member ID Required.
Suggested fix
In joinGroup, handle MemberIdRequired by extracting the member ID from the response and retrying:
response, err := conn.joinGroup(request)
if err == nil && response.ErrorCode != 0 {
if Error(response.ErrorCode) == MemberIDRequired && response.MemberID != "" {
request.MemberID = response.MemberID
response, err = conn.joinGroup(request)
if err == nil && response.ErrorCode != 0 {
err = Error(response.ErrorCode)
}
} else {
err = Error(response.ErrorCode)
}
}
Alternatively, handle it in the nextGeneration error switch by not clearing the member ID for this specific error.
References
Summary
The
ConsumerGroupimplementation doesn't handleMemberIdRequired(error code 79) per KIP-394. When a broker returns this error with an assigned member ID in the response, the client should retry the JoinGroup request using that member ID. Instead, the current code treats it as a fatal error, discards the member ID, and retries with an empty string, creating an infinite failure loop.Root cause
In
consumergroup.go, thejoinGroupmethod (line ~941) treats any non-zero error code as fatal:The caller
nextGenerationthen hits thedefaultcase in the error switch, which clears the member ID and retries after a backoff:default: _ = cg.leaveGroup(memberID) memberID = "" backoff = time.After(cg.config.JoinGroupBackoff)The member ID returned in the
MemberIdRequiredresponse is never preserved.Expected behavior
Per KIP-394, when the broker returns
MemberIdRequired:MemberIDfrom the JoinGroup responseHow to reproduce
Connect a
ConsumerGroupto a Kafka-compatible broker that enforces KIP-394 (e.g., Tansu). The consumer group will fail to join and retry indefinitely with[79] Member ID Required.Suggested fix
In
joinGroup, handleMemberIdRequiredby extracting the member ID from the response and retrying:Alternatively, handle it in the
nextGenerationerror switch by not clearing the member ID for this specific error.References
joingroup_test.go,syncgroup_test.go) already handleMemberIDRequiredcorrectly with a retry loop, but the high-levelConsumerGroupdoes not.