{"record":{"id":"d65bf346e8c17a43","repo":"apache/seatunnel","slug":"plugin-s-not-found","errorCode":null,"errorMessage":"Plugin %s not found.","messagePattern":"Plugin (.+?) not found\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"seatunnel-plugin-discovery/src/main/java/org/apache/seatunnel/plugin/discovery/AbstractPluginDiscovery.java","lineNumber":270,"sourceCode":"            if (pluginInstance != null) {\n                log.info(\n                        \"Load plugin: {} from path: {} use classloader: {}\",\n                        pluginIdentifier,\n                        pluginJarPaths.get(),\n                        classLoader.getClass().getName());\n                return Optional.of(pluginInstance);\n            }\n        }\n        return Optional.empty();\n    }\n\n    @Override\n    public T createPluginInstance(PluginIdentifier pluginIdentifier, Collection<URL> pluginJars) {\n        Optional<T> instance = createOptionalPluginInstance(pluginIdentifier, pluginJars);\n        if (instance.isPresent()) {\n            return instance.get();\n        }\n        throw new RuntimeException(\"Plugin \" + pluginIdentifier + \" not found.\");\n    }\n\n    @Override\n    public ImmutableTriple<PluginIdentifier, List<Option<?>>, List<Option<?>>> getOptionRules(\n            String pluginIdentifier) {\n        Optional<Map.Entry<PluginIdentifier, OptionRule>> pluginEntry =\n                getPlugins().entrySet().stream()\n                        .filter(\n                                entry ->\n                                        entry.getKey()\n                                                .getPluginName()\n                                                .equalsIgnoreCase(pluginIdentifier))\n                        .findFirst();\n        if (pluginEntry.isPresent()) {\n            Map.Entry<PluginIdentifier, OptionRule> entry = pluginEntry.get();\n            List<Option<?>> requiredOptions =\n                    entry.getValue().getRequiredOptions().stream()\n                            .flatMap(requiredOption -> requiredOption.getOptions().stream())","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-plugin-discovery/src/main/java/org/apache/seatunnel/plugin/discovery/AbstractPluginDiscovery.java#L252-L288","documentation":"AbstractPluginDiscovery.createPluginInstance throws a RuntimeException('Plugin <identifier> not found.') when createOptionalPluginInstance returns empty — i.e. no plugin class implementing the requested plugin identifier could be located via the plugin mapping config or discovered SPI files, even after considering the supplied plugin jars.","triggerScenarios":"Requesting a plugin by PluginIdentifier (engine type + plugin name) whose name is absent from plugin-mapping.properties, whose class is not on the classpath/plugin dir, or whose jar was not provided/found; also when the mapped class fails to load/instantiate so the Optional is empty.","commonSituations":"Typo in the plugin name in the job config (e.g. 'Jdbc-mydb' vs 'Jdbc'); connector jar not installed under $SEATUNNEL_HOME/connectors; version mismatch where the plugin identifier changed between SeaTunnel versions; custom plugin missing META-INF/services registration.","solutions":["Check plugin-mapping.properties under $SEATUNNEL_HOME/connectors contains an entry mapping the plugin name to its factory class","Install the connector jar: run sh bin/install-plugin.sh <version> or copy the jar to the connectors directory","Verify the exact plugin name in your job config against the discovered plugin list; fix typos and case","For custom plugins, ensure META-INF/services/<FactoryClass> SPI registration exists and the class is public with a no-arg constructor"],"exampleFix":"// before (job config)\nsink {\n  Jdbc-mydb { ... }   // typo / unregistered name\n}\n\n// after\nsink {\n  Jdbc {\n    url = \"jdbc:mysql://...\"\n    ...\n  }\n}","handlingStrategy":"validation","validationCode":"Properties mapping = new Properties();\nmapping.load(new FileInputStream(\"$SEATUNNEL_HOME/connectors/plugin-mapping.properties\"));\nif (!mapping.containsKey(engineType + \".\" + pluginName)) {\n    throw new IllegalStateException(\"Plugin not registered: \" + pluginName);\n}","typeGuard":"boolean pluginRegistered(Properties pluginMapping, PluginIdentifier id) {\n    return pluginMapping.containsKey(id.getPluginEngineType() + \".\" + id.getPluginName());\n}","tryCatchPattern":"try {\n    T plugin = discovery.createPluginInstance(pluginIdentifier, pluginJars);\n} catch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Plugin \") && e.getMessage().endsWith(\" not found.\")) {\n        throw new IllegalStateException(\"Install jar / check plugin name: \" + pluginIdentifier, e);\n    }\n    throw e;\n}","preventionTips":["Verify plugin names against plugin-mapping.properties before submitting jobs","Run sh bin/install-plugin.sh to install connector jars after upgrading SeaTunnel","For custom plugins, always register META-INF/services SPI files and a public no-arg constructor"],"tags":["plugin-discovery","spi","classpath","configuration"],"backgroundTag":"resource-not-found","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}