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
- Give your custom implementation a unique name in its SPI descriptor (do not reuse 'rocketmq'/'kafka').
- Remove the older/duplicate connector jar so each name maps to exactly one class.
- 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
- Give custom implementations unique SPI names.
- Do not keep two versions of the same connector jar in plugin/ and lib/.
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
- Extension instance(name: {}, class: {}) could not be instan
- Extension instance(name: ${name}, class: ${type}) could not
- Error when load extension class(interface: ${type}, class li
- Extension type == null
- Extension type({}) is not interface!
AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14).
Data as JSON: /api/errors/d12578a4009128d8.
Report an issue: GitHub.