pentaho/pentaho-kettle · error · KettlePluginException
Unexpected error loading class with name
Error message
Unexpected error loading class with name: ${className} What it means
Generic wrapper thrown at the end of the registry's loadClass(PluginInterface, String): any Exception raised inside the method (ClassNotFound from ucl.loadClass, the class-loader errors above, security exceptions) is rethrown as 'Unexpected error loading class with name: <className>' with the original as cause. It signals that resolving or loading the plugin's class failed for an unclassified reason.
Solutions
- Read the chained cause to distinguish ClassNotFoundException (fix class name/jar) from the class-loader errors (fix plugin registration).
- Confirm the fully-qualified class name matches the compiled class inside the plugin jar (javap -cp plugin.jar ... or unzip -l).
- Ensure the plugin folder/jars are deployed and scanned by the registry at startup.
- Update plugin.xml/@Step annotation class attributes after package or class renames.
Example fix
// before @Step(id = "MyStep", name = "My Step", classNmae = "com.acme.MyStepp") // after @Step(id = "MyStep", name = "My Step", className = "com.acme.MyStep")
Defensive patterns
Strategy: try-catch
Validate before calling
String cls = className == null ? plugin.getMainClass() : className;
if (cls == null || cls.isEmpty()) throw new IllegalArgumentException("No class name for plugin " + plugin);
// confirm class presence in the plugin's loader
try { PluginRegistry.getInstance().getClassLoader(plugin).loadClass(cls); } catch (ClassNotFoundException e) { /* resolve before real call */ } Type guard
boolean pluginClassExists(PluginInterface plugin, String className) {
try {
ClassLoader cl = PluginRegistry.getInstance().getClassLoader(plugin);
cl.loadClass(className);
return true;
} catch (Exception e) { return false; }
} Try / catch
try {
T obj = PluginRegistry.getInstance().loadClass(plugin, className, MyInterface.class);
} catch (KettlePluginException e) {
Throwable cause = e.getCause(); // ClassNotFoundException vs loader-missing
LOG.error("loadClass failed for " + className + ": " + cause, e);
throw new PluginDeploymentException(className, e);
} Prevention
- Keep @Step/@JobEntry annotation class attributes in sync with refactored class names.
- Verify fully-qualified names with unzip -l / javap before shipping a plugin.
- Never swallow the cause chain — log e.getCause() to tell 'wrong class name' from 'missing loader'.
When it happens
Trigger: Calling PluginRegistry.loadClass(PluginInterface, String className) where the class name is wrong/absent from the plugin jar, the plugin's class loader is missing (errors 311/312), or Class.forName on a native plugin fails; the inner exception is wrapped and rethrown here.
Common situations: See trigger scenarios.
Related errors
- PLUGINREGISTRY007
- Error creating class for : + ic[i].getName()
- Error executing UserDefinedJavaClass.getFields():
- PLUGINREGISTRY004
- PLUGINREGISTRY005
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/c44115d15ec8f48c.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/plugins/PluginRegistry.java:883
} else {
ucl = folderBasedClassLoaderMap.get( plugin.getPluginDirectory().toString() );
}
}
if ( ucl != null ) {
classLoaders.put( plugin, ucl ); // save for later use...
}
} finally {
lock.writeLock().unlock();
}
if ( ucl == null ) {
throw new KettlePluginException( "Unable to find class loader for plugin: " + plugin );
}
return (T) ucl.loadClass( className );
}
} catch ( Exception e ) {
throw new KettlePluginException( "Unexpected error loading class with name: " + className, e );
}
}
/**
* Load the class with a certain name using the class loader of certain plugin.
*
* @param plugin The plugin for which we want to use the class loader
* @param classType The type of class to load
* @return the name of the class
* @throws KettlePluginException In case there is something wrong
*/
@SuppressWarnings( "unchecked" )
public <T> T getClass( PluginInterface plugin, T classType ) throws KettlePluginException {
String className = plugin.getClassMap().get( classType );
return (T) getClass( plugin, className );
}
/**View on GitHub (pinned to f3058517a1)