apache/kafka · error · KafkaException
The assignor name: '{assignorName}' is used in more than one
Error message
The assignor name: '{assignorName}' is used in more than one assignor: {firstClass}, {secondClass} What it means
Thrown by ConsumerPartitionAssignor.getAssignorInstances when two distinct assignor classes registered via partition.assignment.strategy expose the same name() string. Each assignor must have a unique name because the coordinator uses the name to route the assignment protocol; a duplicate would make assignment ambiguous.
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 c31c9215e1)
Solutions
- Inspect the value of partition.assignment.strategy and remove the duplicate assignor class so each name() appears once.
- If you intentionally keep both classes, override name() on your custom assignor to return a unique string.
- Check for shaded/duplicate dependency JARs on the classpath that ship the same assignor implementation and exclude the redundant one.
Example fix
// before
props.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG,
Arrays.asList(CooperativeStickyAssignor.class.getName(), MyStickyAssignor.class.getName())); // MyStickyAssignor.name() == "cooperative-sticky"
// after
props.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG,
Collections.singletonList(CooperativeStickyAssignor.class.getName())); // or give MyStickyAssignor a unique name() Defensive patterns
Strategy: validation
Validate before calling
// Before building the consumer: dedupe the partition.assignment.strategy entries by assignor name()
List<ConsumerPartitionAssignor> deduped = new ArrayList<>();
Set<String> seenNames = new HashSet<>();
for (Object entry : assignorList) {
ConsumerPartitionAssignor a = instantiate(entry); // your own loader
if (!seenNames.add(a.name())) {
throw new IllegalStateException("Duplicate assignor name '" + a.name() + "' in partition.assignment.strategy");
}
deduped.add(a);
}
props.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG,
deduped.stream().map(a -> a.getClass().getName()).collect(Collectors.toList())); Try / catch
// Wrap consumer construction; the exception surfaces when KafkaConsumer resolves assignors
try {
this.consumer = new KafkaConsumer<>(props);
} catch (KafkaException e) {
if (e.getMessage() != null && e.getMessage().contains("is used in more than one assignor")) {
// log, drop the duplicate assignor from props, and retry / fail fast
}
throw e;
} Prevention
- Keep partition.assignment.strategy as a short, hand-curated list; do not merge multiple assignor lists blindly.
- Every ConsumerPartitionAssignor must return a unique name() — audit custom assignors before registering them.
- Do not list both a cooperative and an eager variant that happen to share the same name() string.
- If you must combine assignors, run them through a name-dedupe step before handing the list to KafkaConsumer.
When it happens
Trigger: Listing two classes in partition.assignment.strategy whose name() collides, e.g. configuring both a custom assignor and a wrapped/cooperative variant that returns the same name, or loading the same logical assignor via two different shaded/jar copies.
Common situations: Upgrading from eager to cooperative assignors and leaving both on the classpath; bundling duplicate copies of an assignor (shaded deps); misconfigured custom assignor that hard-codes an existing name like 'range' or 'cooperative-sticky'.
Related errors
- {klass} ClassNotFoundException exception occurred
- {klass} is not an instance of org.apache.kafka.clients.consu
- List contains element of type {className}, expected String o
- Invalid value null for configuration key.deserializer: must
- Invalid value null for configuration value.deserializer: mus
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/812e0c2a563a0f39.json.
Report an issue: GitHub.