apache/kafka · error · IllegalStateException
Offsets from multiple consumer groups were requested. Use pa
Error message
Offsets from multiple consumer groups were requested. Use partitionsToOffsetAndMetadata(groupId) instead to get future for a specific group.
What it means
Thrown by ListConsumerGroupOffsetsResult.partitionsToOffsetAndMetadata() (the no-arg overload) when the underlying result carries futures for more than one consumer group. The no-arg accessor is only valid when exactly one group was queried; when listConsumerGroupOffsets was called with a Map of multiple group keys, you must disambiguate by passing the specific groupId to the partitionsToOffsetAndMetadata(String) overload (or call all() for the full multi-group result).
Source
Thrown at clients/src/main/java/org/apache/kafka/clients/admin/ListConsumerGroupOffsetsResult.java:53
* <p>
*/
@InterfaceAudience.Public
public class ListConsumerGroupOffsetsResult {
final Map<String, KafkaFuture<Map<TopicPartition, OffsetAndMetadata>>> futures;
ListConsumerGroupOffsetsResult(final Map<CoordinatorKey, KafkaFuture<Map<TopicPartition, OffsetAndMetadata>>> futures) {
this.futures = futures.entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey().idValue, Entry::getValue));
}
/**
* 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,View on GitHub (pinned to c31c9215e1)
Solutions
- Call partitionsToOffsetAndMetadata(groupId) with the specific group you want from the multi-group result.
- Or call all() to obtain a future yielding Map<String, Map<TopicPartition, OffsetAndMetadata>> for every requested group.
- If the intent truly is a single group, call listConsumerGroupOffsets(singleGroupId) (or a one-entry map) so the no-arg accessor remains valid.
Example fix
// before
ListConsumerGroupOffsetsResult result =
admin.listConsumerGroupOffsets(Map.of("g1", Set.of(tp), "g2", Set.of(tp)));
Map<TopicPartition, OffsetAndMetadata> offsets =
result.partitionsToOffsetAndMetadata().get(); // IllegalStateException
// after - pick a specific group
Map<TopicPartition, OffsetAndMetadata> g1Offsets =
result.partitionsToOffsetAndMetadata("g1").get();
// or get every group at once
Map<String, Map<TopicPartition, OffsetAndMetadata>> all =
result.all().get(); Defensive patterns
Strategy: validation
Validate before calling
ListConsumerGroupOffsetsResult result = admin.listConsumerGroupOffsets(requestedGroups);
if (requestedGroups.size() != 1) {
// multi-group: use all() or partitionsToOffsetAndMetadata(groupId) per group
Map<String, Map<TopicPartition, OffsetAndMetadata>> all = result.all().get();
} else {
Map<TopicPartition, OffsetAndMetadata> single =
result.partitionsToOffsetAndMetadata(requestedGroups.iterator().next()).get();
} Try / catch
if (result.futures().size() == 1) {
result.partitionsToOffsetAndMetadata(); // safe
} else {
// multiple groups requested -> call partitionsToOffsetAndMetadata(groupId) or all()
result.all().get();
} Prevention
- The no-arg partitionsToOffsetAndMetadata() requires exactly one group; always prefer the partitionsToOffsetAndMetadata(groupId) overload unless you control the request size.
- Track how many groups you passed to listConsumerGroupOffsets and branch on size before consuming the result.
- For batch listings, use result.all() instead of assuming a single-group shape.
When it happens
Trigger: Calling admin.listConsumerGroupOffsets(Map.of(groupA, partitions, groupB, partitions)) and then invoking .partitionsToOffsetAndMetadata() on the result without a groupId; the futures map has size 2, so the no-arg accessor throws IllegalStateException.
Common situations: Refactoring single-group offset tooling to a multi-group batch query without switching the accessor overload; generic helper that always calls the no-arg partitionsToOffsetAndMetadata regardless of how many groups were requested; copying example code that assumed a single group.
Related errors
- The TopicCollection: {topics} provided did not match any sup
- The TopicCollection: {topics} provided did not match any sup
- Partition {partition} was not included in the original reque
- The timeout cannot be negative.
- Cannot request fenced brokers from controller endpoint
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/85f84623b101b836.json.
Report an issue: GitHub.