apache/seatunnel · warning

plugin dir: {} not exists, load plugin from classpath

Error message

plugin dir: {} not exists, load plugin from classpath

What it means

getPluginFactories expects the configured plugin directory (e.g., connectors/) to exist so it can build a URLClassLoader over its jars. If the directory does not exist, it logs this warning and instead discovers factories from the thread context classpath, which usually contains only core classes — typically leading to 'plugin not found' errors later.

Source

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

    }

    protected List<Factory> getPluginFactories() {
        List<Factory> factories;
        if (this.pluginDir.toFile().exists()) {
            log.debug("load plugin from plugin dir: {}", this.pluginDir);
            List<URL> files;
            try {
                files = FileUtils.searchJarFiles(this.pluginDir);
            } catch (IOException e) {
                throw new RuntimeException(
                        String.format(
                                "Can not find any plugin(source/sink/transform) in the dir: %s",
                                this.pluginDir));
            }
            factories =
                    FactoryUtil.discoverFactories(new URLClassLoader(files.toArray(new URL[0])));
        } else {
            log.warn("plugin dir: {} not exists, load plugin from classpath", this.pluginDir);
            factories =
                    FactoryUtil.discoverFactories(Thread.currentThread().getContextClassLoader());
        }
        return factories;
    }

    protected T loadPluginInstance(PluginIdentifier pluginIdentifier, ClassLoader classLoader) {
        ServiceLoader<T> serviceLoader = ServiceLoader.load(getPluginBaseClass(), classLoader);
        for (T t : serviceLoader) {
            if (t instanceof PluginIdentifierInterface) {
                // new api
                PluginIdentifierInterface pluginIdentifierInstance = (PluginIdentifierInterface) t;
                if (StringUtils.equalsIgnoreCase(
                        pluginIdentifierInstance.getPluginName(),
                        pluginIdentifier.getPluginName())) {
                    return (T) pluginIdentifierInstance;
                }
            } else {

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Set SEATUNNEL_HOME correctly on every node so the connectors/ dir resolves
  2. Run sh bin/install-plugin.sh <version> to download connector jars into the plugin dir
  3. If you intentionally ship connectors on the classpath, confirm the connector jar is inside lib/ or the app classpath
  4. Verify the plugin dir path in your config/CLI (e.g., --name uses correct connector identifier once dir exists)

Example fix

// before: missing dir
export SEATUNNEL_HOME=/opt/seatunnel  # connectors/ absent
// after
sh bin/install-plugin.sh 2.3.x
ls $SEATUNNEL_HOME/connectors/connector-console-*.jar
Defensive patterns

Strategy: validation

Validate before calling

File pluginDir = new File(System.getenv("SEATUNNEL_HOME"), "connectors");
if (!pluginDir.isDirectory()) throw new IllegalStateException("install connectors: " + pluginDir);

Prevention

When it happens

Trigger: The pluginDir passed to AbstractPluginDiscovery (derived from SEATUNNEL_HOME/connectors or a -Dplugin config) does not exist on the node starting the job.

Common situations: SEATUNNEL_HOME not set or wrong on a cluster node; connector never installed (install-plugin.sh not run); running from IDE/source without connectors dir; fat-jar deployment without plugin dirs.

Related errors


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