apache/kafka · error · IllegalArgumentException

Offsets for consumer group '{groupId}' were not requested.

Error message

Offsets for consumer group '{groupId}' were not requested.

What it means

Thrown by ListConsumerGroupOffsetsResult.partitionsToOffsetAndMetadata(groupId) when the requested groupId was not part of the original listConsumerGroupOffsets request. The Admin client builds a future per requested group; asking for a group that was not requested is a programming error caught client-side before any broker interaction.

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/admin/ListConsumerGroupOffsetsResult.java:66

     * Return a future which yields a map of topic partitions to OffsetAndMetadata objects.
     * If the group does not have a committed offset for this partition, the corresponding value in the returned map will be null.
     */
    public KafkaFuture<Map<TopicPartition, OffsetAndMetadata>> partitionsToOffsetAndMetadata() {
        if (futures.size() != 1) {
            throw new IllegalStateException("Offsets from multiple consumer groups were requested. " +
                    "Use partitionsToOffsetAndMetadata(groupId) instead to get future for a specific group.");
        }
        return futures.values().iterator().next();
    }

    /**
     * Return a future which yields a map of topic partitions to OffsetAndMetadata objects for
     * the specified group. If the group doesn't have a committed offset for a specific
     * partition, the corresponding value in the returned map will be null.
     */
    public KafkaFuture<Map<TopicPartition, OffsetAndMetadata>> partitionsToOffsetAndMetadata(String groupId) {
        if (!futures.containsKey(groupId))
            throw new IllegalArgumentException("Offsets for consumer group '" + groupId + "' were not requested.");
        return futures.get(groupId);
    }

    /**
     * Return a future which yields all {@code Map<String, Map<TopicPartition, OffsetAndMetadata>} objects,
     * if requests for all the groups succeed.
     */
    public KafkaFuture<Map<String, Map<TopicPartition, OffsetAndMetadata>>> all() {
        return KafkaFuture.allOf(futures.values().toArray(new KafkaFuture<?>[0])).thenApply(
            nil -> {
                Map<String, Map<TopicPartition, OffsetAndMetadata>> listedConsumerGroupOffsets = new HashMap<>(futures.size());
                futures.forEach((key, future) -> {
                    try {
                        listedConsumerGroupOffsets.put(key, future.get());
                    } catch (InterruptedException | ExecutionException e) {
                        // This should be unreachable, since the KafkaFuture#allOf already ensured
                        // that all of the futures completed successfully.
                        throw new RuntimeException(e);

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Ensure the groupId passed to partitionsToOffsetAndMetadata exactly matches one of the keys used in the listConsumerGroupOffsets request
  2. If you requested multiple groups, iterate the result of all() or pass each requested key individually instead of guessing
  3. Use partitionsToOffsetAndMetadata() (no-arg) only when exactly one group was requested; otherwise pass the specific group id

Example fix

// before
ListConsumerGroupOffsetsResult r = admin.listConsumerGroupOffsets(Map.of("g1", opts));
r.partitionsToOffsetAndMetadata("g2"); // throws

// after
r.partitionsToOffsetAndMetadata("g1");
// or, for multiple groups:
r.all().get().forEach((g, m) -> process(g, m));
Defensive patterns

Strategy: validation

Validate before calling

// Track the groupIds you passed to listConsumerGroupOffsets up front.
Set<String> requestedGroupIds = new HashSet<>(groupIds); // the set given to admin.listConsumerGroupOffsets(...)
String groupId = ...;
if (!requestedGroupIds.contains(groupId)) {
    // caller bug: this group was not part of the request; handle/log and skip
    return;
}
ListConsumerGroupOffsetsResult result = admin.listConsumerGroupOffsets(requestedGroupIds);
result.partitionsToOffsetAndMetadata(groupId).get();

Type guard

// Narrow a request key to one actually present in the requested set.
static Optional<String> requestedGroup(Set<String> requested, String groupId) {
    return groupId != null && requested.contains(groupId) ? Optional.of(groupId) : Optional.empty();
}

Try / catch

try {
    result.partitionsToOffsetAndMetadata(groupId).get();
} catch (IllegalArgumentException e) {
    // groupId was not in the original listConsumerGroupOffsets request set;
    // fix the caller's bookkeeping rather than retrying.
    log.warn("Skipping group {} - not part of listConsumerGroupOffsets request", groupId);
}

Prevention

When it happens

Trigger: Calling result.partitionsToOffsetAndMetadata("g2") after Admin.listConsumerGroupOffsets was invoked with a different group (e.g. "g1" or a Map that did not include "g2"). Also happens when a typo or stale variable is passed as the groupId, or when the multi-group listConsumerGroupOffsets(Map) overload is used but the per-group accessor is called with a key not in that map.

Common situations: Refactoring code from single-group to multi-group listing and forgetting to update the accessor call; passing a group id loaded from a different config key than the one used in the request; copy-paste between services where the requested set and the queried set drift apart.

Related errors


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