apache/kafka · error · KafkaException
The assignor name: ' ' is used in more than one assignor
Error message
The assignor name: '{assignorName}' is used in more than one assignor: {existing}, {current} What it means
Thrown by ConsumerPartitionAssignor.getAssignorInstances while building the partition assignor list from the 'partition.assignment.strategy' consumer config. Each assignor exposes a name() string; Kafka requires these names to be unique within one consumer because the assignor name is used as a protocol identifier during the JoinGroup. Two entries in the config whose classes return the same name() collide, and construction aborts before the consumer starts.
Solutions
- Inspect the full partition.assignment.strategy value and remove duplicate class entries or classes that share a name().
- If you ship a custom assignor, verify its name() returns a unique string distinct from org.apache.kafka.clients.consumer.* defaults (range, roundrobin, sticky, cooperative-sticky).
- Read the error's {existing} and {current} class names to see exactly which two classes collide, then drop one from the config.
- When wrapping an assignor, override name() to a new value rather than delegating to the wrapped instance.
Example fix
// before
props.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG,
List.of(CooperativeStickyAssignor.class.getName(),
CooperativeStickyAssignor.class.getName())); // duplicated
// after
props.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG,
List.of(CooperativeStickyAssignor.class.getName())); Defensive patterns
Strategy: validation
Validate before calling
// before building the consumer, validate assignor names are unique
List<ConsumerPartitionAssignor> probes = configuredStrategies.stream()
.map(s -> { try { return (ConsumerPartitionAssignor) Utils.newInstance(Utils.loadClass(s, Object.class)); }
catch (ClassNotFoundException e) { throw new IllegalStateException("Unknown assignor class " + s, e); } })
.collect(Collectors.toList());
Set<String> names = new HashSet<>();
for (ConsumerPartitionAssignor a : probes) {
if (!names.add(a.name()))
throw new IllegalStateException("Duplicate assignor name: " + a.name());
} Type guard
// n/a: validated at config-load time via the probe above
Try / catch
try {
consumer = new KafkaConsumer<>(props);
} catch (KafkaException e) {
if (e.getMessage() != null && e.getMessage().contains("is used in more than one assignor")) {
// log, dedupe partition.assignment.strategy, and fail fast with a clear config error
}
throw e;
} Prevention
- Centralize partition.assignment.strategy in one config builder and add a uniqueness check on the resolved assignor names.
- For custom assignors, write a unit test asserting name() returns a unique constant.
- Avoid listing both eager and cooperative assignors in the same list during migrations; follow the documented order.
When it happens
Trigger: Listing the same class twice in partition.assignment.strategy (e.g. [org.apache.kafka.clients.consumer.CooperativeStickyAssignor, org.apache.kafka.clients.consumer.CooperativeStickyAssignor]); listing two different custom assignors whose name() methods return the same literal; wrapping/decorating an existing assignor but forgetting to override name(); upgrading to a Kafka version where a built-in assignor's name() changed and now matches another one you configured.
Common situations: Migrating from eager to cooperative assignors and leaving both StickyAssignor and CooperativeStickyAssignor in the list; copy-paste of a custom assignor class with a duplicated name field; fat-jar shading that bundles two versions of an assignor; mixing a third-party assignor with a built-in one that shares its name.
Related errors
- is not an instance of…
- List contains element of type
- ClassNotFoundException exception occurred
- MaxPollRecords must be strictly superior to 0
- Cannot add records for a partition that is not assigned to…
AI-assisted analysis of apache/kafka@996fb4585a (2026-08-11).
Data as JSON: /api/errors/d5b9af6a9260b9c8.
Report an issue: GitHub.
Appendix: source
Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/ConsumerPartitionAssignor.java:441
for (Object klass : assignorClasses) {
// first try to get the class if passed in as a string
if (klass instanceof String) {
try {
klass = Utils.loadClass((String) klass, Object.class);
} catch (ClassNotFoundException classNotFound) {
throw new KafkaException(klass + " ClassNotFoundException exception occurred", classNotFound);
}
}
if (klass instanceof Class<?>) {
Object assignor = Utils.newInstance((Class<?>) klass);
if (assignor instanceof Configurable)
((Configurable) assignor).configure(configs);
if (assignor instanceof ConsumerPartitionAssignor) {
String assignorName = ((ConsumerPartitionAssignor) assignor).name();
if (assignorNameMap.containsKey(assignorName)) {
throw new KafkaException("The assignor name: '" + assignorName + "' is used in more than one assignor: " +
assignorNameMap.get(assignorName) + ", " + assignor.getClass().getName());
}
assignorNameMap.put(assignorName, assignor.getClass().getName());
assignors.add((ConsumerPartitionAssignor) assignor);
} else {
throw new KafkaException(klass + " is not an instance of " + ConsumerPartitionAssignor.class.getName());
}
} else {
throw new KafkaException("List contains element of type " + klass.getClass().getName() + ", expected String or Class");
}
}
return assignors;
}
}
View on GitHub (pinned to 996fb4585a)