{"id":"2d768c518ebd4279","repo":"apache/kafka","slug":"must-configure-at-least-one-partition-assigner-cla","errorCode":null,"errorMessage":"Must configure at least one partition assigner class name to {} configuration property","messagePattern":"Must configure at least one partition assigner class name to (.+?) configuration property","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/ClassicKafkaConsumer.java","lineNumber":1274,"sourceCode":"        if (threadId != currentThread.get() && !currentThread.compareAndSet(NO_CURRENT_THREAD, threadId))\n            throw new ConcurrentModificationException(\"KafkaConsumer is not safe for multi-threaded access. \" +\n                    \"currentThread(name: \" + thread.getName() + \", id: \" + threadId + \")\" +\n                    \" otherThread(id: \" + currentThread.get() + \")\"\n            );\n        refcount.incrementAndGet();\n    }\n\n    /**\n     * Release the light lock protecting the consumer from multi-threaded access.\n     */\n    private void release() {\n        if (refcount.decrementAndGet() == 0)\n            currentThread.set(NO_CURRENT_THREAD);\n    }\n\n    private void throwIfNoAssignorsConfigured() {\n        if (assignors.isEmpty())\n            throw new IllegalStateException(\"Must configure at least one partition assigner class name to \" +\n                    ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG + \" configuration property\");\n    }\n\n    private void throwIfGroupIdNotDefined() {\n        if (groupId.isEmpty())\n            throw new InvalidGroupIdException(\"To use the group management or offset commit APIs, you must \" +\n                    \"provide a valid \" + ConsumerConfig.GROUP_ID_CONFIG + \" in the consumer configuration.\");\n    }\n\n    private void updateLastSeenEpochIfNewer(TopicPartition topicPartition, OffsetAndMetadata offsetAndMetadata) {\n        if (offsetAndMetadata != null)\n            offsetAndMetadata.leaderEpoch().ifPresent(epoch -> metadata.updateLastSeenEpochIfNewer(topicPartition, epoch));\n    }\n\n    // Functions below are for testing only\n    @Override\n    public String clientId() {\n        return clientId;","sourceCodeStart":1256,"sourceCodeEnd":1292,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/ClassicKafkaConsumer.java#L1256-L1292","documentation":"IllegalStateException thrown by ClassicKafkaConsumer.throwIfNoAssignorsConfigured() (ClassicKafkaConsumer.java:1272) when subscribe(Collection) or subscribe(Pattern) is called and the assignor list ended up empty. The assignor list is built from the partition.assignment.strategy config (default RangeAssignor + CooperativeStickyAssignor); if the user explicitly sets it blank or supplies only class names that fail to instantiate/are filtered out, no strategy remains to compute partitions for the group, so the library refuses to subscribe.","triggerScenarios":"Calling subscribe(Collection<String>) or subscribe(Pattern) on a consumer whose partition.assignment.strategy resolved to no usable assignor. The check fires from subscribeInternal at ClassicKafkaConsumer.java:506 (topic list) and :582 (pattern).","commonSituations":"Copy-pasting config and dropping the default assignors; intentionally disabling group management by setting partition.assignment.strategy to an empty string but still calling subscribe(); a custom ConsumerPartitionAssignor class missing from the classpath and silently dropped during instantiation; YAML/env interpolation (e.g. ${ASSIGNORS:-} expanding to empty).","solutions":["Set partition.assignment.strategy to at least one valid ConsumerPartitionAssignor class name (e.g. org.apache.kafka.clients.consumer.CooperativeStickyAssignor), or simply omit the property to take the defaults.","If you do not need group management, call assign(Collection<TopicPartition>) instead of subscribe(...); manual assignment does not require an assignor.","For custom assignors, confirm the class is on the classpath, has a public no-arg constructor, and that its name() does not collide with a built-in."],"exampleFix":"// before\nprops.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG, \"\");\nconsumer.subscribe(Arrays.asList(\"orders\"));   // throws IllegalStateException\n\n// after — pick a real assignor, or use manual assignment\nprops.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG,\n    CooperativeStickyAssignor.class.getName());\nconsumer.subscribe(Arrays.asList(\"orders\"));\n\n// or, if group management is not required:\nconsumer.assign(Arrays.asList(new TopicPartition(\"orders\", 0)));","handlingStrategy":"validation","validationCode":"// Ensure at least one partition assignor is configured before subscribe()\nString assignors = props.getProperty(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG);\nif (assignors != null && assignors.trim().isEmpty()) {\n    // empty value is the dangerous case; drop it to fall back to the default RangeAssignor\n    props.remove(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG);\n}","typeGuard":null,"tryCatchPattern":"try {\n    consumer.subscribe(topics);\n} catch (IllegalStateException e) {\n    // partition.assignment.strategy was blanked/invalid; reconfigure and rebuild\n    props.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG,\n              RangeAssignor.class.getName());\n    consumer = new KafkaConsumer<>(props);\n}","preventionTips":["Never set partition.assignment.strategy to an empty string.","If overriding the default, include at least one known-good class (RangeAssignor, CooperativeStickyAssignor, StickyAssignor).","Validate the consumer config against a known schema at startup before constructing the consumer."],"tags":["configuration","consumer","assignor"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}