{"record":{"id":"b96bd24438000212","repo":"apache/seatunnel","slug":"multiple-factories-for-identifier-s-that-implem","errorCode":null,"errorMessage":"Multiple factories for identifier '%s' that implement '%s' found in the classpath.\n\nAmbiguous factory classes are:\n\n%s","messagePattern":"Multiple factories for identifier '(.+?)' that implement '(.+?)' found in the classpath\\.\n\nAmbiguous factory classes are:\n\n(.+?)","errorType":"validation","errorClass":"FactoryException","httpStatus":null,"severity":"error","filePath":"seatunnel-api/src/main/java/org/apache/seatunnel/api/table/factory/FactoryUtil.java","lineNumber":379,"sourceCode":"                                    + \"%s\",\n                            factoryIdentifier,\n                            factoryClass.getName(),\n                            foundFactories.stream()\n                                    .map(Factory::factoryIdentifier)\n                                    .distinct()\n                                    .sorted()\n                                    .collect(Collectors.joining(\"\\n\"))));\n        }\n\n        checkMultipleMatchingFactories(factoryIdentifier, factoryClass, matchingFactories);\n\n        return matchingFactories.get(0);\n    }\n\n    private static <T extends Factory> void checkMultipleMatchingFactories(\n            String factoryIdentifier, Class<T> factoryClass, List<T> matchingFactories) {\n        if (matchingFactories.size() > 1) {\n            throw new FactoryException(\n                    String.format(\n                            \"Multiple factories for identifier '%s' that implement '%s' found in the classpath.\\n\\n\"\n                                    + \"Ambiguous factory classes are:\\n\\n\"\n                                    + \"%s\",\n                            factoryIdentifier,\n                            factoryClass.getName(),\n                            matchingFactories.stream()\n                                    .map(f -> f.getClass().getName())\n                                    .sorted()\n                                    .collect(Collectors.joining(\"\\n\"))));\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T extends Factory> List<T> discoverFactories(\n            ClassLoader classLoader, Class<T> factoryClass) {\n        return discoverFactories(classLoader).stream()\n                .filter(f -> factoryClass.isAssignableFrom(f.getClass()))","sourceCodeStart":361,"sourceCodeEnd":397,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/factory/FactoryUtil.java#L361-L397","documentation":"FactoryUtil.checkMultipleMatchingFactories throws this FactoryException when more than one factory on the classpath claims the same factoryIdentifier for the requested factory interface. Discovery is then ambiguous, so it fails fast and lists the competing classes.","triggerScenarios":"discoverFactory or discoverOptionalFactory finds 2+ factories whose factoryIdentifier() equals the requested identifier, typically because two different connector jars or two versions of the same connector are on the classpath.","commonSituations":"Multiple connector jar versions in $SEATUNNEL_HOME/connectors; a custom plugin copied under a different jar name with the same identifier; stale plugins left after an upgrade.","solutions":["List the ambiguous classes in the message and delete the duplicate/outdated jar from the connectors directory.","Keep only one version of each connector jar in $SEATUNNEL_HOME/connectors/plugin-mapping layout.","If intentionally overriding a plugin, ensure only one jar with that identifier is visible to the classloader."],"exampleFix":"// before\nconnectors/connector-jdbc-2.3.3.jar\nconnectors/connector-jdbc-2.3.5.jar\n// after\nconnectors/connector-jdbc-2.3.5.jar  # remove the older jar","handlingStrategy":"validation","validationCode":"List<Factory> matching = FactoryUtil.discoverFactories(classLoader).stream()\n    .filter(f -> f.factoryIdentifier().equalsIgnoreCase(pluginId)).collect(Collectors.toList());\nif (matching.size() > 1) throw new IllegalStateException(\"Duplicate plugin jars for identifier: \" + pluginId);","typeGuard":null,"tryCatchPattern":"try {\n    return FactoryUtil.discoverFactory(cl, TableSourceFactory.class, id);\n} catch (FactoryException e) {\n    throw new IllegalStateException(\"Remove duplicate connector jars listed in the error\", e);\n}","preventionTips":["Keep exactly one jar per connector identifier in the connectors directory.","Delete old jars after upgrading connectors.","Avoid copying connector jars into multiple locations visible to the same classloader."],"tags":["spi","duplicate-plugin","classpath","factory"],"backgroundTag":"conflicting-config-options","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}