pentaho/pentaho-kettle · error · KettlePluginException
PLUGINREGISTRY008
PLUGINREGISTRY008
Error message
Error creating class loader
What it means
KettlePluginException with code PLUGINREGISTRY008 thrown by PluginRegistry.createClassLoader as the catch-all for any unexpected Throwable while building the plugin's URLClassLoader. Unlike PLUGINREGISTRY006 it is not limited to MalformedURLException - any error during classloader assembly (e.g. SecurityException, NPE on a null jar path) lands here after being printed to stderr.
Solutions
- Read the stderr stack trace printed before the exception and the wrapped cause to identify the real failure
- Ensure the jarFiles list passed to createClassLoader contains no null entries and the plugin folder is non-null
- Check for SecurityManager / container policies blocking ClassLoader creation
- Verify plugin metadata (plugin.xml / annotation) is intact for the plugin being loaded
Example fix
// before
ClassLoader ucl = PluginRegistry.init().createClassLoader(plugin, null); // plugin folder may be null
// after
if ( plugin.getPluginDirectory() != null && new File( plugin.getPluginDirectory() ).exists() ) {
ClassLoader ucl = PluginRegistry.init().createClassLoader( plugin, null );
} Defensive patterns
Strategy: try-catch
Validate before calling
PluginInterface plugin = ...;
boolean ok = plugin != null
&& plugin.getPluginDirectory() != null
&& new java.io.File( plugin.getPluginDirectory().getPath() ).exists();
if ( !ok ) throw new IllegalStateException("plugin or its folder is not resolvable"); Type guard
static boolean canCreateClassLoader(PluginInterface p) {
return p != null && p.getPluginDirectory() != null && p.getJarFiles() != null;
} Try / catch
try {
ClassLoader ucl = registry.createClassLoader(plugin, null);
} catch ( KettlePluginException e ) {
if ( e.getMessage().contains("PLUGINREGISTRY008") ) {
log.error("Unexpected classloader failure for plugin " + plugin.getName(), e.getCause());
}
} Prevention
- Never pass null jarFiles entries to createClassLoader
- Run PDI without a restrictive SecurityManager or grant createClassLoader permissions
- Validate plugin folders and metadata before initialization
- Keep plugin jar layouts conforming to the PDI plugin directory convention (lib/ subdir)
When it happens
Trigger: Calling PluginRegistry.createClassLoader when anything other than URL parsing fails: a null entry in the jarFiles list, a SecurityManager denying classloader creation, or an unexpected runtime exception while resolving the plugin folder URL.
Common situations: Null or empty jar file paths passed programmatically; running under a restrictive security policy or container that forbids new classloaders; corrupted plugin registration metadata producing NPEs; plugin API version mismatch causing registry state surprises.
Related errors
- PLUGINREGISTRY006
- Error creating plugin class
- Unable to get instance of plugin type
- A server socket allocation always has to accompanied by a…
- A server socket allocation always has to accompanied by a…
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/47e8c64f5c7a3d3b.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/plugins/PluginRegistry.java:1000
inverseClassLoaderLookup.computeIfAbsent( ucl, k -> new HashSet<>() ).add( plugin );
}
}
}
}
}
} finally {
lock.writeLock().unlock();
}
// Load the class.
return ucl;
}
} catch ( MalformedURLException e ) {
throw new KettlePluginException( BaseMessages.getString(
PKG, "PluginRegistry.RuntimeError.MalformedURL.PLUGINREGISTRY006" ), e );
} catch ( Throwable e ) {
e.printStackTrace();
throw new KettlePluginException( BaseMessages.getString(
PKG, "PluginRegistry.RuntimeError.UnExpectedCreatingClassLoader.PLUGINREGISTRY008" ), e );
}
}
/**
* Allows the tracking of plugins as they come and go.
*
* @param typeToTrack extension of PluginTypeInterface to track.
* @param listener receives notification when a plugin of the specified type is added/removed/modified
* @param <T> extension of PluginTypeInterface
*/
public <T extends PluginTypeInterface> void addPluginListener( Class<T> typeToTrack, PluginTypeListener listener ) {
lock.writeLock().lock();
try {
Set<PluginTypeListener> list = listeners.computeIfAbsent( typeToTrack, k -> new HashSet<>() );
list.add( listener );
} finally {
lock.writeLock().unlock();View on GitHub (pinned to f3058517a1)