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

  1. Inspect the full partition.assignment.strategy value and remove duplicate class entries or classes that share a name().
  2. 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).
  3. Read the error's {existing} and {current} class names to see exactly which two classes collide, then drop one from the config.
  4. 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

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


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)