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

  1. Pass the exact same MemberToRemove instance (or an equal one) to memberResult that you placed in RemoveMembersFromConsumerGroupOptions.
  2. If you only care about overall success, call result.all() instead of per-member memberResult().
  3. Iterate over the members you originally requested instead of fabricating new MemberToRemove objects from another API response.
  4. 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

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


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/b15085df27d5ff33.json. Report an issue: GitHub.