apache/seatunnel · error · RuntimeException

Plugin %s not found.

Error message

Plugin %s not found.

What it means

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.

Source

Thrown at seatunnel-plugin-discovery/src/main/java/org/apache/seatunnel/plugin/discovery/AbstractPluginDiscovery.java:270

            if (pluginInstance != null) {
                log.info(
                        "Load plugin: {} from path: {} use classloader: {}",
                        pluginIdentifier,
                        pluginJarPaths.get(),
                        classLoader.getClass().getName());
                return Optional.of(pluginInstance);
            }
        }
        return Optional.empty();
    }

    @Override
    public T createPluginInstance(PluginIdentifier pluginIdentifier, Collection<URL> pluginJars) {
        Optional<T> instance = createOptionalPluginInstance(pluginIdentifier, pluginJars);
        if (instance.isPresent()) {
            return instance.get();
        }
        throw new RuntimeException("Plugin " + pluginIdentifier + " not found.");
    }

    @Override
    public ImmutableTriple<PluginIdentifier, List<Option<?>>, List<Option<?>>> getOptionRules(
            String pluginIdentifier) {
        Optional<Map.Entry<PluginIdentifier, OptionRule>> pluginEntry =
                getPlugins().entrySet().stream()
                        .filter(
                                entry ->
                                        entry.getKey()
                                                .getPluginName()
                                                .equalsIgnoreCase(pluginIdentifier))
                        .findFirst();
        if (pluginEntry.isPresent()) {
            Map.Entry<PluginIdentifier, OptionRule> entry = pluginEntry.get();
            List<Option<?>> requiredOptions =
                    entry.getValue().getRequiredOptions().stream()
                            .flatMap(requiredOption -> requiredOption.getOptions().stream())

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Check plugin-mapping.properties under $SEATUNNEL_HOME/connectors contains an entry mapping the plugin name to its factory class
  2. Install the connector jar: run sh bin/install-plugin.sh <version> or copy the jar to the connectors directory
  3. Verify the exact plugin name in your job config against the discovered plugin list; fix typos and case
  4. For custom plugins, ensure META-INF/services/<FactoryClass> SPI registration exists and the class is public with a no-arg constructor

Example fix

// before (job config)
sink {
  Jdbc-mydb { ... }   // typo / unregistered name
}

// after
sink {
  Jdbc {
    url = "jdbc:mysql://..."
    ...
  }
}
Defensive patterns

Strategy: validation

Validate before calling

Properties mapping = new Properties();
mapping.load(new FileInputStream("$SEATUNNEL_HOME/connectors/plugin-mapping.properties"));
if (!mapping.containsKey(engineType + "." + pluginName)) {
    throw new IllegalStateException("Plugin not registered: " + pluginName);
}

Type guard

boolean pluginRegistered(Properties pluginMapping, PluginIdentifier id) {
    return pluginMapping.containsKey(id.getPluginEngineType() + "." + id.getPluginName());
}

Try / catch

try {
    T plugin = discovery.createPluginInstance(pluginIdentifier, pluginJars);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Plugin ") && e.getMessage().endsWith(" not found.")) {
        throw new IllegalStateException("Install jar / check plugin name: " + pluginIdentifier, e);
    }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/d65bf346e8c17a43. Report an issue: GitHub.