{"record":{"id":"401090d11207b6f8","repo":"jd-opensource/joyagent-jdgenie","slug":"multiple-jdbc-dialect-factories-can-handle","errorCode":null,"errorMessage":"Multiple jdbc dialect factories can handle","messagePattern":"Multiple jdbc dialect factories can handle","errorType":"exception","errorClass":"JdbcBizException","httpStatus":null,"severity":"error","filePath":"genie-backend/src/main/java/com/jd/genie/data/jdbc/catalog/JdbcCatalogLoader.java","lineNumber":35,"sourceCode":"\n\n    public static JdbcCatalog load(DialectEnum jdbcDialect) {\n        ClassLoader cl = Thread.currentThread().getContextClassLoader();\n        List<JdbcCatalogFactory> foundFactories = discoverFactories(cl);\n\n        if (foundFactories.isEmpty()) {\n            throw new JdbcBizException(String.format(\n                    \"Could not find any jdbc dialect factories that implement '%s' in the classpath.\",\n                    JdbcCatalog.class.getName()));\n        }\n\n        final List<JdbcCatalogFactory> matchingFactories =\n                foundFactories.stream().filter(f -> f.jdbcDialect() == jdbcDialect).toList();\n        if (matchingFactories.isEmpty()) {\n            throw new CatalogException(\"Could not find any jdbc dialect factory that can handled \");\n        }\n        if (matchingFactories.size() > 1) {\n            throw new JdbcBizException(\"Multiple jdbc dialect factories can handle\");\n        }\n\n        return matchingFactories.get(0).createCatalog();\n    }\n\n\n    private static List<JdbcCatalogFactory> discoverFactories(ClassLoader classLoader) {\n        try {\n            final List<JdbcCatalogFactory> result = new LinkedList<>();\n            ServiceLoader.load(JdbcCatalogFactory.class, classLoader)\n                    .iterator()\n                    .forEachRemaining(result::add);\n            return result;\n        } catch (ServiceConfigurationError e) {\n            log.error(\"Could not load service provider for Catalog factory.\", e);\n            throw new JdbcBizException(\n                    \"Could not load service provider for Catalog factory.\", e);\n        }","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/jd-opensource/joyagent-jdgenie/blob/2417e0b8b636d941ad5fb14c59b20dddfef5375d/genie-backend/src/main/java/com/jd/genie/data/jdbc/catalog/JdbcCatalogLoader.java#L17-L53","documentation":"JdbcCatalogLoader.load throws JdbcBizException('Multiple jdbc dialect factories can handle') when more than one discovered JdbcCatalogFactory claims the same DialectEnum. The loader refuses to guess between ambiguous providers.","triggerScenarios":"load(dialect) where two or more factories on the classpath return jdbcDialect() equal to the requested dialect — typically caused by duplicate/conflicting provider jars (two versions of the same dialect module, or two modules claiming the same dialect).","commonSituations":"Dependency mediation pulled in two versions of the same dialect artifact; a custom factory registered alongside the stock one for the same dialect; fat-jar merging multiple META-INF/services entries from different jars.","solutions":["Run mvn dependency:tree (or gradle dependencies) and exclude duplicate dialect provider jars.","Remove or de-register the redundant JdbcCatalogFactory service registration.","If intentional, change the loader to select a preferred factory deterministically instead of throwing."],"exampleFix":"// before (pom.xml)\n<dependency>genie-data-jdbc-mysql:1.0</dependency>\n<dependency>genie-data-jdbc-mysql-legacy:1.2</dependency> <!-- also registers mysql factory -->\n// after (pom.xml)\n<dependency>genie-data-jdbc-mysql:1.2</dependency>\n<!-- legacy jar excluded -->","handlingStrategy":"try-catch","validationCode":"// detect duplicate providers before load\nlong count = discoverFactories(cl).stream()\n    .filter(f -> f.jdbcDialect() == dialect).count();\nif (count > 1) {\n    throw new IllegalStateException(\"Duplicate dialect provider for \" + dialect);\n}","typeGuard":null,"tryCatchPattern":"try {\n    JdbcCatalog catalog = JdbcCatalogLoader.load(dialect);\n} catch (JdbcBizException e) {\n    if (e.getMessage().contains(\"Multiple jdbc dialect factories\")) {\n        // run dependency:tree, exclude duplicate jar, rebuild\n    } else throw e;\n}","preventionTips":["Check dependency tree for duplicate dialect artifacts on every build.","Register only one factory per DialectEnum.","Pin dialect provider versions via dependencyManagement/BOM.","Test catalog loading in CI to catch packaging duplicates."],"tags":["java","jdbc","spi","classpath","duplicate-providers"],"backgroundTag":"internal-invariant-violation","analyzedSha":"2417e0b8b636d941ad5fb14c59b20dddfef5375d","analyzedAt":"2026-09-08T11:28:19.414Z","contentChangedAt":"2026-09-08T11:28:19.414Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}