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
- Ensure the job runs with the standard Flink runtime classloader (URLClassLoader-based)
- Avoid embedding the starter in environments that override the context classloader
- 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
- Run on standard Flink runtime classloaders
- Do not override the thread context classloader when embedding the starter
- Keep custom classloaders extending URLClassLoader
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
- Unsupported classloader:
- All candidate sink tables were skipped in Flink starter.
- All candidate sink tables were skipped in Flink starter.
- can't load jar use current thread classloader, use…
- checkpoint.interval is set to
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)