alibaba/canal · error · IllegalStateException

Duplicate extension ${type.getName()} name ${n} on ${c.getNa

Error message

Duplicate extension ${type.getName()} name ${n} on ${c.getName()} and ${clazz.getName()}

What it means

Constructed in loadFile when two DIFFERENT implementation classes are registered under the same name within the extension map (extensionClasses.get(n) != clazz). Like 215, this exception is created then caught by the inner catch(Throwable) at ExtensionLoader.java:381 and stored into 'exceptions' rather than propagated; the duplicate-name entry is removed and the extension may become unavailable, surfacing later as 'could not be found' (209/211).

Source

Thrown at connector/core/src/main/java/com/alibaba/otter/canal/connector/core/spi/ExtensionLoader.java:370

                                                                                + clazz.getName()
                                                                                + "is not subtype of interface.");
                                            } else {
                                                try {
                                                    clazz.getConstructor(type);
                                                } catch (NoSuchMethodException e) {
                                                    clazz.getConstructor();
                                                    String[] names = NAME_SEPARATOR.split(name);
                                                    if (names != null && names.length > 0) {
                                                        for (String n : names) {
                                                            if (!cachedNames.containsKey(clazz)) {
                                                                cachedNames.put(clazz, n);
                                                            }
                                                            Class<?> c = extensionClasses.get(n);
                                                            if (c == null) {
                                                                extensionClasses.put(n, clazz);
                                                            } else if (c != clazz) {
                                                                cachedNames.remove(clazz);
                                                                throw new IllegalStateException("Duplicate extension "
                                                                                                + type.getName()
                                                                                                + " name " + n + " on "
                                                                                                + c.getName() + " and "
                                                                                                + clazz.getName());
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    } catch (Throwable t) {
                                        IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: "
                                                                                            + type
                                                                                            + ", class line: "
                                                                                            + line
                                                                                            + ") in "
                                                                                            + url
                                                                                            + ", cause: "

View on GitHub (pinned to 87be50e876)

Solutions

  1. Give your custom implementation a unique name in its SPI descriptor (do not reuse 'rocketmq'/'kafka').
  2. Remove the older/duplicate connector jar so each name maps to exactly one class.
  3. Inspect plugin/ and lib/ for two jars providing the same SPI descriptor entry.

Example fix

# before: two jars both declare
#   rocketmq=com.alibaba...CanalRocketMQProducer  (built-in)
#   rocketmq=com.myco.MyRocketProducer            (custom)
# after (custom jar):
my-rocketmq=com.myco.MyRocketProducer
Defensive patterns

Strategy: validation

Validate before calling

// Detect duplicate names across descriptors before deploying
Map<String,String> nameToImpl = new HashMap<>();
for (String descriptorLine : allDescriptorLines(interfaceType)) {
    String name = namePart(descriptorLine);
    String impl = implPart(descriptorLine);
    if (nameToImpl.containsKey(name) && !nameToImpl.get(name).equals(impl)) {
        throw new IllegalStateException("duplicate SPI name " + name);
    }
    nameToImpl.put(name, impl);
}

Try / catch

// NOTE: thrown-and-stored at load time; surfaces later as 'could not be found'.
try {
    loader.getExtension(name, spiDir, standbyDir);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("could not be found")) {
        // grep logs: 'Duplicate extension' -> rename custom impl or remove old jar
    }
    throw e;
}

Prevention

When it happens

Trigger: Two SPI descriptor entries (across META-INF/canal and META-INF/services, or across plugin jars) bind the same name to distinct classes; a custom jar duplicates a name already provided by a built-in jar.

Common situations: Dropping a custom producer jar into plugin/ that reuses the name 'rocketmq'/'kafka' already mapped by the bundled connector jar; two versions of the same connector jar present simultaneously.

Related errors


AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14). Data as JSON: /api/errors/d12578a4009128d8. Report an issue: GitHub.