{"record":{"id":"0a53e084ff4b0f54","repo":"apache/seatunnel","slug":"can-t-support-custom-load-jar","errorCode":null,"errorMessage":"can't support custom load jar","messagePattern":"can't support custom load jar","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"seatunnel-plugin-discovery/src/main/java/org/apache/seatunnel/plugin/discovery/AbstractPluginDiscovery.java","lineNumber":85,"sourceCode":"import java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\n@Slf4j\n@SuppressWarnings(\"unchecked\")\npublic abstract class AbstractPluginDiscovery<T> implements PluginDiscovery<T> {\n\n    private static final String PLUGIN_MAPPING_FILE = \"plugin-mapping.properties\";\n\n    /**\n     * Add jar url to classloader. The different engine should have different logic to add url into\n     * their own classloader\n     */\n    private static final BiConsumer<ClassLoader, List<URL>> DEFAULT_URL_TO_CLASSLOADER =\n            (classLoader, urls) -> {\n                if (classLoader instanceof URLClassLoader) {\n                    urls.forEach(url -> ReflectionUtils.invoke(classLoader, \"addURL\", url));\n                } else {\n                    throw new UnsupportedOperationException(\"can't support custom load jar\");\n                }\n            };\n\n    private final Path pluginDir;\n    private final Config pluginMappingConfig;\n    private final BiConsumer<ClassLoader, List<URL>> addURLToClassLoaderConsumer;\n    protected final ConcurrentHashMap<PluginIdentifier, Optional<List<URL>>> pluginJarPath =\n            new ConcurrentHashMap<>(Common.COLLECTION_SIZE);\n    protected final Map<PluginIdentifier, String> sourcePluginInstance;\n    protected final Map<PluginIdentifier, String> sinkPluginInstance;\n    protected final Map<PluginIdentifier, String> transformPluginInstance;\n\n    public AbstractPluginDiscovery(BiConsumer<ClassLoader, List<URL>> addURLToClassloader) {\n        this(Common.connectorDir(), loadConnectorPluginConfig(), addURLToClassloader);\n    }\n\n    public AbstractPluginDiscovery() {\n        this(Common.connectorDir(), loadConnectorPluginConfig());","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-plugin-discovery/src/main/java/org/apache/seatunnel/plugin/discovery/AbstractPluginDiscovery.java#L67-L103","documentation":"AbstractPluginDiscovery's DEFAULT_URL_TO_CLASSLOADER adds plugin jar URLs to a classloader via reflection, but only when the classloader is a URLClassLoader. On modern JDKs (9+) the application classloader is not a URLClassLoader, so any attempt to add custom plugin jar URLs throws UnsupportedOperationException('can't support custom load jar'). This fires in the discovery constructor when dynamic plugin jar loading is requested.","triggerScenarios":"Constructing an AbstractPluginDiscovery subclass with plugin jar URLs while running on a JDK whose application classloader is not a URLClassLoader (Java 9+), i.e. dynamic 'custom load jar' is requested but unsupported by the runtime.","commonSituations":"Running SeaTunnel on JDK 9+ where custom plugin jar loading was attempted; configuring plugin jar paths on a runtime that does not support adding URLs; launching the engine in a mode that expects dynamic jar injection.","solutions":["Place the plugin jar into the SeaTunnel plugin directory (connectors/ or lib/) so it is loaded at startup instead of dynamically","Run on a JDK/mode where the classloader is a URLClassLoader, or launch with a custom URLClassLoader setup","Remove the plugin jar path configuration so discovery uses classpath-based loading"],"exampleFix":"// before (config referencing external jar)\nplugin_jar_paths = [\"/opt/my/custom-connector.jar\"]\n\n// after\n# remove the jar path config; install the jar instead:\ncp /opt/my/custom-connector.jar $SEATUNNEL_HOME/connectors/","handlingStrategy":"fallback","validationCode":"ClassLoader cl = Thread.currentThread().getContextClassLoader();\nboolean dynamicJarLoadingSupported = cl instanceof URLClassLoader;\nif (!dynamicJarLoadingSupported) {\n    // do not configure plugin jar URLs; place jars in the plugin dir instead\n}","typeGuard":"boolean supportsDynamicJarAdd(ClassLoader cl) {\n    return cl instanceof URLClassLoader;\n}","tryCatchPattern":"try {\n    discovery = new MyPluginDiscovery(pluginDir, pluginJars);\n} catch (UnsupportedOperationException e) {\n    if (\"can't support custom load jar\".equals(e.getMessage())) {\n        log.warn(\"Dynamic jar loading unsupported on this JDK; install jars into the plugin dir instead\");\n    } else {\n        throw e;\n    }\n}","preventionTips":["Install plugins into $SEATUNNEL_HOME/connectors or lib instead of runtime jar injection","On JDK 9+ never rely on adding URLs to the app classloader","Document that custom jar paths require a URLClassLoader-based launch"],"tags":["classpath","plugin-discovery","jdk","unsupported-operation"],"backgroundTag":"unsupported-platform","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"}