{"record":{"id":"110af71f80f24478","repo":"apache/dubbo","slug":"duplicate-extension-name-on-and","errorCode":null,"errorMessage":"Duplicate extension {} name {} on {} and {}","messagePattern":"Duplicate extension (.+?) name (.+?) on (.+?) and (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java","lineNumber":1358,"sourceCode":"            cachedNames.put(clazz, name);\n        }\n    }\n\n    /**\n     * put clazz in extensionClasses\n     */\n    private void saveInExtensionClass(\n            Map<String, Class<?>> extensionClasses, Class<?> clazz, String name, boolean overridden) {\n        Class<?> c = extensionClasses.get(name);\n        if (c == null || overridden) {\n            extensionClasses.put(name, clazz);\n        } else if (c != clazz) {\n            // duplicate implementation is unacceptable\n            unacceptableExceptions.add(name);\n            String duplicateMsg = \"Duplicate extension \" + type.getName() + \" name \" + name + \" on \" + c.getName()\n                    + \" and \" + clazz.getName();\n            logger.error(COMMON_ERROR_LOAD_EXTENSION, \"\", \"\", duplicateMsg);\n            throw new IllegalStateException(duplicateMsg);\n        }\n    }\n\n    /**\n     * cache Activate class which is annotated with <code>Activate</code>\n     * <p>\n     * for compatibility, also cache class with old alibaba Activate annotation\n     */\n    @SuppressWarnings(\"deprecation\")\n    private void cacheActivateClass(Class<?> clazz, String name) {\n        Activate activate = clazz.getAnnotation(Activate.class);\n        if (activate != null) {\n            cachedActivates.put(name, activate);\n        } else if (Dubbo2CompactUtils.isEnabled() && Dubbo2ActivateUtils.isActivateLoaded()) {\n            // support com.alibaba.dubbo.common.extension.Activate\n            Annotation oldActivate = clazz.getAnnotation(Dubbo2ActivateUtils.getActivateClass());\n            if (oldActivate != null) {\n                cachedActivates.put(name, oldActivate);","sourceCodeStart":1340,"sourceCodeEnd":1376,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java#L1340-L1376","documentation":"Thrown by saveInExtensionClass() when two distinct implementation classes are registered under the same SPI name and the second registration is not marked overridden. Dubbo disallows two different classes for one name within a single ExtensionLoader; the first wins and the conflicting second triggers this error. It is also logged via COMMON_ERROR_LOAD_EXTENSION and the name is added to unacceptableExceptions, which makes later getExtension(name) throw findException instead of returning either.","triggerScenarios":"Two jars on the classpath both provide a META-INF SPI config line with the same name key but different implementation class FQNs. For example, dubbo-rpc-dubbo and a custom jar both declare 'dubbo=com.xxx.ProtocolImpl'. Without overridden=true on the later load, the duplicate is detected in saveInExtensionClass.","commonSituations":"Including a custom extension jar that reuses a built-in Dubbo extension name (e.g., redefining 'dubbo' Protocol); two versions of the same Dubbo module jar on the classpath providing duplicate SPI entries; a fat-jar that bundles conflicting transitive SPI configs.","solutions":["Identify which jars provide the duplicate name using 'jar tf <jar> | grep META-INF/dubbo' and remove or rename one.","Rename your custom extension to a unique name in its META-INF SPI config (e.g., 'mydubbo=com.example.MyProtocol').","If overriding is intentional, use the overridden=true path (Dubbo's loading strategy / @SPI value ordering) so the later config replaces the earlier one rather than conflicting.","Run mvn dependency:tree to find duplicate versions of dubbo-* artifacts and exclude the stale one."],"exampleFix":"# before: two jars both declare\n# jar1: META-INF/dubbo/...Protocol -> dubbo=com.a.A\n# jar2: META-INF/dubbo/...Protocol -> dubbo=com.b.B\n# throws [148]\n\n# after: rename in the custom jar\n# jar2: META-INF/dubbo/...Protocol -> mydubbo=com.b.B","handlingStrategy":"validation","validationCode":"// Detect duplicate SPI names across classpath at startup\nMap<String, List<URL>> seen = new HashMap<>();\nEnumeration<URL> urls = cl.getResources(\"META-INF/dubbo/\" + iface.getName());\nwhile (urls.hasMoreElements()) {\n    parseLines(urls.nextElement()).forEach((k, v) ->\n        seen.computeIfAbsent(k, x -> new ArrayList<>()).add(v));\n}\nseen.forEach((k, v) -> { if (new HashSet<>(v).size() > 1) log.warn(\"duplicate SPI name {}: {}\", k, v); });","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use unique extension names for custom implementations; do not reuse built-in Dubbo names.","Run mvn dependency:tree to catch duplicate dubbo-* artifact versions.","Audit META-INF SPI configs across all jars with 'jar tf' when integrating a new module."],"tags":["dubbo-spi","duplicate","classpath-conflict","extension-loader"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}