apache/kafka · error · IllegalStateException

User configured {} to empty while trying to subscribe for gr

Error message

User configured {} to empty while trying to subscribe for group protocol to auto assign partitions

What it means

Thrown as an IllegalStateException inside ConsumerCoordinator.poll when the subscription is in auto-assignment mode (the app called subscribe() for group-managed partition assignment) but the internal protocol field is null. protocol is null precisely when ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG was resolved to an empty assignor list, so the consumer has no strategy to negotiate partition assignment with the group coordinator. The library refuses to poll because group management cannot proceed without at least one assignor.

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/internals/ConsumerCoordinator.java:520

     * Poll for coordinator events. This ensures that the coordinator is known and that the consumer
     * has joined the group (if it is using group management). This also handles periodic offset commits
     * if they are enabled.
     * <p>
     * Returns early if the timeout expires or if waiting on rejoin is not required
     *
     * @param timer Timer bounding how long this method can block
     * @param waitForJoinGroup Boolean flag indicating if we should wait until re-join group completes
     * @throws KafkaException if the rebalance callback throws an exception
     * @return true iff the operation succeeded
     */
    public boolean poll(Timer timer, boolean waitForJoinGroup) {
        maybeUpdateSubscriptionMetadata();

        invokeCompletedOffsetCommitCallbacks();

        if (subscriptions.hasAutoAssignedPartitions()) {
            if (protocol == null) {
                throw new IllegalStateException("User configured " + ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG +
                    " to empty while trying to subscribe for group protocol to auto assign partitions");
            }
            // Always update the heartbeat last poll time so that the heartbeat thread does not leave the
            // group proactively due to application inactivity even if (say) the coordinator cannot be found.
            pollHeartbeat(timer.currentTimeMs());
            if (coordinatorUnknownAndUnreadySync(timer)) {
                return false;
            }

            if (rejoinNeededOrPending()) {
                // due to a race condition between the initial metadata fetch and the initial rebalance,
                // we need to ensure that the metadata is fresh before joining initially. This ensures
                // that we have matched the pattern against the cluster's topics at least once before joining.
                if (subscriptions.hasPatternSubscription()) {
                    // For consumer group that uses pattern-based subscription, after a topic is created,
                    // any consumer that discovers the topic after metadata refresh can trigger rebalance
                    // across the entire consumer group. Multiple rebalances can be triggered after one topic
                    // creation if consumers refresh metadata at vastly different times. We can significantly

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Set partition.assignment.strategy to at least one valid assignor class, e.g. org.apache.kafka.clients.consumer.CooperativeStickyAssignor (and RangeAssignor for eager).
  2. If you want the defaults, simply omit partition.assignment.strategy so the client applies RangeAssignor,CooperativeStickyAssignor.
  3. Verify the assignor class is on the classpath and spelled correctly (FQN) so it is not silently dropped during config parsing.
  4. Use manual assignment (KafkaConsumer#assign) instead of subscribe() if you truly do not want group-based assignment.

Example fix

// before
props.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG, "");
consumer.subscribe(Arrays.asList("orders"));

// after
props.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG,
    CooperativeStickyAssignor.class.getName());
consumer.subscribe(Arrays.asList("orders"));
Defensive patterns

Strategy: validation

Validate before calling

List<String> strategies =
    (List<String>) configs.get(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG);
boolean empty = strategies == null || strategies.isEmpty()
    || strategies.stream().allMatch(s -> s == null || s.trim().isEmpty());
if (empty && Boolean.TRUE.equals(configs.get("group.protocol") == null
        || "classic".equalsIgnoreCase(String.valueOf(configs.get("group.protocol"))))) {
    throw new IllegalArgumentException(
        "partition.assignment.strategy must be non-empty when using group-based auto assignment");
}

Try / catch

try {
    consumer.poll(Duration.ofMillis(1000));
} catch (IllegalStateException e) {
    if (e.getMessage() != null && e.getMessage().contains("partition.assignment.strategy")) {
        // config is empty: rebuild consumer with an explicit assignor
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Application sets partition.assignment.strategy to an empty string/list (or a list whose entries all fail to load/resolve to no assignor) and then calls KafkaConsumer.subscribe(Collection). On the first poll() the check subscriptions.hasAutoAssignedPartitions() is true while protocol == null, raising the exception at line 520.

Common situations: Explicitly clearing partition.assignment.strategy to override defaults; passing a property placeholder that resolves to empty; frameworks (Spring) that replace the default assignors with a custom one whose class is not on the classpath, leaving the resolved list empty; copying config snippets that omit the strategy.

Related errors


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