apache/seatunnel · error · RuntimeException

Unsupported classloader

Error message

Unsupported classloader: ${classLoaderClassName}

What it means

RuntimeException thrown by FlinkAbstractPluginExecuteProcessor's classloader-wrapper when it tries to add plugin jar URLs to the current classloader via reflection (addURL method) but the classloader is not a URLClassLoader (or equivalent) supporting addURL. It wraps the reflective invocation exception and names the unsupported classloader class.

Solutions

  1. Ensure the job runs with the standard Flink runtime classloader (URLClassLoader-based)
  2. Avoid embedding the starter in environments that override the context classloader
  3. If a custom classloader is required, make it extend URLClassLoader or expose an addURL-equivalent method
Defensive patterns

Strategy: validation

Validate before calling

ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (!(cl instanceof URLClassLoader)) {
    throw new IllegalStateException("Job requires a URLClassLoader-based context classloader, got: " + cl.getClass().getName());
}

Type guard

boolean isUrlClassLoader(ClassLoader cl) {
    return cl instanceof URLClassLoader;
}

Try / catch

try {
    processor.execute();
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Unsupported classloader")) {
        log.error("Context classloader lacks addURL: {}", e.getCause(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Running the Flink starter on an environment where the context classloader is not a URLClassLoader (e.g. Flink's child-first or an application-server classloader without addURL), so method lookup or invoke fails inside the Callable.

Common situations: Embedding SeaTunnel in another application with a custom classloader; Flink version changes replacing URLClassLoader; running inside containers that swap the thread context classloader.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at seatunnel-core/seatunnel-flink-starter/seatunnel-flink-starter-common/src/main/java/org/apache/seatunnel/core/starter/flink/execution/FlinkAbstractPluginExecuteProcessor.java:65

                    urls.forEach(url -> ReflectionUtils.invoke(classLoader, "addURL", url));
                } else {
                    try {
                        // In Java 8, AppClassLoader is a subclass of URLClassLoader, so classLoader
                        // instanceof URLClassLoader will return true. However, in Java 11, due to
                        // the introduction of the modular system, AppClassLoader is no longer a
                        // subclass of URLClassLoader, and this check will return false. To be
                        // compatible with both Java 8 and Java 11, we can use reflection to
                        // dynamically call the addURL method of URLClassLoader.
                        Optional<Method> method =
                                ReflectionUtils.getDeclaredMethod(
                                        URLClassLoader.class, "addURL", URL.class);
                        if (method.isPresent()) {
                            for (URL url : urls) {
                                method.get().invoke(classLoader, url);
                            }
                        }
                    } catch (Exception e) {
                        throw new RuntimeException(
                                "Unsupported classloader: " + classLoader.getClass().getName(), e);
                    }
                }
            };

    protected FlinkRuntimeEnvironment flinkRuntimeEnvironment;
    protected final List<? extends Config> pluginConfigs;
    protected JobContext jobContext;
    protected final List<T> plugins;
    protected final Config envConfig;
    protected final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

    protected FlinkAbstractPluginExecuteProcessor(
            List<URL> jarPaths,
            Config envConfig,
            List<? extends Config> pluginConfigs,
            JobContext jobContext) {
        this.pluginConfigs = pluginConfigs;

View on GitHub (pinned to cf67b549a7)