{"id":"c8140411c90ff8d8","repo":"apache/kafka","slug":"user-configured-to-empty-while-trying-to-subscr","errorCode":null,"errorMessage":"User configured {} to empty while trying to subscribe for group protocol to auto assign partitions","messagePattern":"User configured (.+?) to empty while trying to subscribe for group protocol to auto assign partitions","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/ConsumerCoordinator.java","lineNumber":520,"sourceCode":"     * Poll for coordinator events. This ensures that the coordinator is known and that the consumer\n     * has joined the group (if it is using group management). This also handles periodic offset commits\n     * if they are enabled.\n     * <p>\n     * Returns early if the timeout expires or if waiting on rejoin is not required\n     *\n     * @param timer Timer bounding how long this method can block\n     * @param waitForJoinGroup Boolean flag indicating if we should wait until re-join group completes\n     * @throws KafkaException if the rebalance callback throws an exception\n     * @return true iff the operation succeeded\n     */\n    public boolean poll(Timer timer, boolean waitForJoinGroup) {\n        maybeUpdateSubscriptionMetadata();\n\n        invokeCompletedOffsetCommitCallbacks();\n\n        if (subscriptions.hasAutoAssignedPartitions()) {\n            if (protocol == null) {\n                throw new IllegalStateException(\"User configured \" + ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG +\n                    \" to empty while trying to subscribe for group protocol to auto assign partitions\");\n            }\n            // Always update the heartbeat last poll time so that the heartbeat thread does not leave the\n            // group proactively due to application inactivity even if (say) the coordinator cannot be found.\n            pollHeartbeat(timer.currentTimeMs());\n            if (coordinatorUnknownAndUnreadySync(timer)) {\n                return false;\n            }\n\n            if (rejoinNeededOrPending()) {\n                // due to a race condition between the initial metadata fetch and the initial rebalance,\n                // we need to ensure that the metadata is fresh before joining initially. This ensures\n                // that we have matched the pattern against the cluster's topics at least once before joining.\n                if (subscriptions.hasPatternSubscription()) {\n                    // For consumer group that uses pattern-based subscription, after a topic is created,\n                    // any consumer that discovers the topic after metadata refresh can trigger rebalance\n                    // across the entire consumer group. Multiple rebalances can be triggered after one topic\n                    // creation if consumers refresh metadata at vastly different times. We can significantly","sourceCodeStart":502,"sourceCodeEnd":538,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/ConsumerCoordinator.java#L502-L538","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set partition.assignment.strategy to at least one valid assignor class, e.g. org.apache.kafka.clients.consumer.CooperativeStickyAssignor (and RangeAssignor for eager).","If you want the defaults, simply omit partition.assignment.strategy so the client applies RangeAssignor,CooperativeStickyAssignor.","Verify the assignor class is on the classpath and spelled correctly (FQN) so it is not silently dropped during config parsing.","Use manual assignment (KafkaConsumer#assign) instead of subscribe() if you truly do not want group-based assignment."],"exampleFix":"// before\nprops.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG, \"\");\nconsumer.subscribe(Arrays.asList(\"orders\"));\n\n// after\nprops.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG,\n    CooperativeStickyAssignor.class.getName());\nconsumer.subscribe(Arrays.asList(\"orders\"));","handlingStrategy":"validation","validationCode":"List<String> strategies =\n    (List<String>) configs.get(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG);\nboolean empty = strategies == null || strategies.isEmpty()\n    || strategies.stream().allMatch(s -> s == null || s.trim().isEmpty());\nif (empty && Boolean.TRUE.equals(configs.get(\"group.protocol\") == null\n        || \"classic\".equalsIgnoreCase(String.valueOf(configs.get(\"group.protocol\"))))) {\n    throw new IllegalArgumentException(\n        \"partition.assignment.strategy must be non-empty when using group-based auto assignment\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    consumer.poll(Duration.ofMillis(1000));\n} catch (IllegalStateException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"partition.assignment.strategy\")) {\n        // config is empty: rebuild consumer with an explicit assignor\n    } else {\n        throw e;\n    }\n}","preventionTips":["Always set partition.assignment.strategy explicitly (e.g. org.apache.kafka.clients.consumer.CooperativeStickyAssignor)","Validate the consumer config map at startup, before constructing KafkaConsumer","Use consumer.assign(...) (manual assignment) if you do not need group-based rebalancing"],"tags":["kafka","consumer","config","consumer-group","partition-assignment"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}