apache/kafka · error · IllegalArgumentException
Member {member} was not included in the original request
Error message
Member {member} was not included in the original request What it means
Thrown by RemoveMembersFromConsumerGroupResult.memberResult(MemberToRemove) when the caller asks for the per-member future of a member that was not part of the MemberToRemove set originally passed to RemoveMembersFromConsumerGroupOptions. The Admin API tracks exactly which members were requested so it can correlate the broker's per-member errors back to the caller; querying an untracked member is a programming error. It is an IllegalArgumentException, surfaced synchronously before any network call.
Source
Thrown at clients/src/main/java/org/apache/kafka/clients/admin/RemoveMembersFromConsumerGroupResult.java:88
return;
}
}
}
result.complete(null);
}
});
return result;
}
/**
* Returns the selected member future.
*/
public KafkaFuture<Void> memberResult(MemberToRemove member) {
if (removeAll()) {
throw new IllegalArgumentException("The method: memberResult is not applicable in 'removeAll' mode");
}
if (!memberInfos.contains(member)) {
throw new IllegalArgumentException("Member " + member + " was not included in the original request");
}
final KafkaFutureImpl<Void> result = new KafkaFutureImpl<>();
this.future.whenComplete((memberErrors, throwable) -> {
if (throwable != null) {
result.completeExceptionally(throwable);
} else if (!maybeCompleteExceptionally(memberErrors, member.toMemberIdentity(), result)) {
result.complete(null);
}
});
return result;
}
private boolean maybeCompleteExceptionally(Map<MemberIdentity, Errors> memberErrors,
MemberIdentity member,
KafkaFutureImpl<Void> result) {
Throwable exception = KafkaAdminClient.getSubLevelError(memberErrors, member,
"Member \"" + member + "\" was not included in the removal response");View on GitHub (pinned to c31c9215e1)
Solutions
- Pass the exact same MemberToRemove instance (or an equal one) to memberResult that you placed in RemoveMembersFromConsumerGroupOptions.
- If you only care about overall success, call result.all() instead of per-member memberResult().
- Iterate over the members you originally requested instead of fabricating new MemberToRemove objects from another API response.
- Double-check MemberToRemove equality semantics: it wraps MemberIdentity (member id + group.instance.id), so both fields must match.
Example fix
// before RemoveMembersFromConsumerGroupOptions opts = new RemoveMembersFromConsumerGroupOptions(List.of(memberA)); RemoveMembersFromConsumerGroupResult res = admin.removeMembersFromConsumerGroup(groupId, opts); res.memberResult(memberB).get(); // throws: memberB not in original request // after RemoveMembersFromConsumerGroupOptions opts = new RemoveMembersFromConsumerGroupOptions(List.of(memberA, memberB)); RemoveMembersFromConsumerGroupResult res = admin.removeMembersFromConsumerGroup(groupId, opts); res.memberResult(memberB).get();
Defensive patterns
Strategy: validation
Validate before calling
// Before calling result.memberResult(member), verify the member was in the original set:
Set<MemberToRemove> requested = options.members(); // or track the set you passed to RemoveMembersFromConsumerGroupOptions
if (!requested.contains(member)) {
// skip memberResult for this member, or re-issue removeMembersFromConsumerGroup with the extended set
log.warn("Skipping memberResult: {} was not in the original RemoveMembersFromConsumerGroupOptions", member);
} else {
result.memberResult(member).get();
} Type guard
// MemberToRemove equality is value-based (instanceId hash). Guard against accidentally passing a new instance:
static boolean wasRequested(Set<MemberToRemove> requested, MemberToRemove m) {
return requested != null && m != null && requested.stream()
.anyMatch(r -> Objects.equals(r.toMemberIdentity().instanceId(), m.toMemberIdentity().instanceId()));
} Try / catch
try {
result.memberResult(member).get();
} catch (ExecutionException e) {
if (e.getCause() instanceof IllegalArgumentException
&& e.getCause().getMessage().contains("was not included in the original request")) {
// member was not part of RemoveMembersFromConsumerGroupOptions; re-issue the admin call with it included
} else { throw e; }
} Prevention
- Keep the exact MemberToRemove set passed to RemoveMembersFromConsumerGroupOptions in a variable and only call memberResult against members drawn from that set.
- When using 'removeAll' mode (empty member set), never call memberResult - it is invalid in that mode.
- Do not reconstruct MemberToRemove from primitive fields (instanceId string) for memberResult; reuse the original instance to avoid equality drift.
When it happens
Trigger: Calling admin.removeMembersFromConsumerGroup(groupId, new RemoveMembersFromConsumerGroupOptions(membersA)).memberResult(memberB) where memberB was not in membersA. Also thrown if memberResult is used in 'removeAll' mode, though that case is caught first by a dedicated guard at line 85.
Common situations: Constructing MemberToRemove from a different source (e.g. group listing from DescribeGroups) than the one used to build the options; reusing a result object after rebuilding the options with a filtered member list; copy-paste of member-identity fields (group.instance.id vs client.id vs member.id) so equals() fails on MemberToRemove.
Related errors
- Unknown topology description status id: {id}
- Expected 0 <= minVersion <= maxVersion but received minVersi
- Topic partitions to assign to cannot have null or empty topi
- RebalanceListener cannot be null
- Topic pattern to subscribe to cannot be null
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/b15085df27d5ff33.json.
Report an issue: GitHub.