pentaho/pentaho-kettle · error · KettlePluginException
Unable to load class
Error message
Unable to load class: ${className} What it means
When scanning a jar-based plugin, BasePluginType loads the plugin's main class with a URLClassLoader built over the plugin jar. If loadClass returns null (or otherwise fails to resolve), KettlePluginException 'Unable to load class: <className>' is thrown. This means the jar declares a plugin main class that cannot actually be loaded from that jar's classloader.
Solutions
- Verify the class named in the message actually exists in the plugin jar (jar tf plugin.jar | grep ClassName).
- Add the plugin's missing dependency jars to its lib folder or the Kettle classpath.
- Rebuild the plugin against your Kettle/JDK version, or run Kettle on the JDK version the plugin was compiled for.
- Replace the plugin jar with a complete, version-compatible build.
Example fix
// before plugins/myplugin/ myplugin.jar // com.acme.Main missing (incomplete build) // after plugins/myplugin/ myplugin.jar // contains com.acme.Main lib/dependency.jar
Defensive patterns
Strategy: validation
Validate before calling
File jar = new File(jarPath);
try (java.util.jar.JarFile jf = new java.util.jar.JarFile(jar)) {
if (jf.getJarEntry(className.replace('.', '/') + ".class") == null) {
throw new IllegalStateException("Class missing from plugin jar: " + className);
}
} Type guard
static boolean classLoadable(String className, ClassLoader cl) {
try { Class.forName(className, false, cl); return true; }
catch (Throwable t) { return false; }
} Try / catch
try {
pluginType.searchPlugins();
} catch (KettlePluginException e) {
log.logError("Plugin class could not be loaded: " + e.getMessage(), e);
} Prevention
- Verify plugin main class exists in the jar before deploying (jar tf).
- Ship all dependency jars alongside the plugin (lib folder).
- Match the plugin's target JDK bytecode version to the runtime JVM.
- Build plugins against the same Kettle version as the runtime.
When it happens
Trigger: searchPlugins()/jar scanning -> new BasePluginType(...)/registerPluginJars where JarFilePlugin.getClassName() names a class absent from the jar, incompatible with the current JVM (bad bytecode version), or whose dependencies are missing so loadClass fails.
Common situations: Plugin jar built for a different Kettle version; incomplete plugin folder missing dependency jars; Java version mismatch (e.g. class compiled for Java 17 on Java 11 runtime); fat-jar shading that stripped plugin classes.
Related errors
- Unable to find native plugins definition file
- Unable to load native plugins
- Could not initialize from codeSnippets.xml
- KettleMissingPluginsException( getErrorMessage(…
- KettleMissingPluginsException( getErrorMessage(…
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/a36a4f4f06a8b4b1.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/plugins/BasePluginType.java:849
* in the lib directory of plugin folders.
*
* @param transverseLibDirs
*/
protected void setTransverseLibDirs( boolean transverseLibDirs ) {
this.searchLibDir = transverseLibDirs;
}
protected void registerPluginJars() throws KettlePluginException {
List<JarFileAnnotationPlugin> jarFilePlugins = findAnnotatedClassFiles( pluginClass.getName() );
for ( JarFileAnnotationPlugin jarFilePlugin : jarFilePlugins ) {
URLClassLoader urlClassLoader =
createUrlClassLoader( jarFilePlugin.getJarFile(), getClass().getClassLoader() );
try {
Class<?> clazz = urlClassLoader.loadClass( jarFilePlugin.getClassName() );
if ( clazz == null ) {
throw new KettlePluginException( "Unable to load class: " + jarFilePlugin.getClassName() );
}
List<String> libraries = Arrays.stream( urlClassLoader.getURLs() )
.map( URL::getFile )
.collect( Collectors.toList() );
Annotation annotation = clazz.getAnnotation( pluginClass );
handlePluginAnnotation( clazz, annotation, libraries, false, jarFilePlugin.getPluginFolder() );
} catch ( Exception e ) {
// Ignore for now, don't know if it's even possible.
LogChannel.GENERAL.logError(
"Unexpected error registering jar plugin file: " + jarFilePlugin.getJarFile(), e );
} finally {
if ( urlClassLoader instanceof KettleURLClassLoader ) {
( (KettleURLClassLoader) urlClassLoader ).closeClassLoader();
}
}
}
}View on GitHub (pinned to f3058517a1)