pentaho/pentaho-kettle · error · KettlePluginException
PLUGINREGISTRY005
PLUGINREGISTRY005
Error message
Illegal access to class
What it means
In loadClass, an IllegalAccessException from cl.newInstance() — the class or its no-arg constructor is not accessible to the registry's caller — is rethrown as KettlePluginException 'Illegal access to class' (PLUGINREGISTRY005). This is a Java access-modifier problem, not a classpath problem.
Solutions
- Make the plugin class public and give it a public no-argument constructor.
- Move nested plugin classes out to top-level public classes.
- Remove private constructors on the class Kettle must instantiate (use init()/lifecycle hooks instead of singleton enforcement).
- On JDK 9+, add the appropriate --add-opens/--add-exports or module exports so the package is accessible.
Example fix
// before
class MyStepMeta extends BaseStepMeta { // package-private
private MyStepMeta() { }
}
// after
public class MyStepMeta extends BaseStepMeta {
public MyStepMeta() { }
} Defensive patterns
Strategy: validation
Validate before calling
Class<?> cl = pluginClassLoader.loadClass(fqn);
int mods = cl.getModifiers();
if (!Modifier.isPublic(mods)) throw new IllegalStateException("Plugin class not public: " + fqn);
Constructor<?> ctor = cl.getDeclaredConstructor();
if (!Modifier.isPublic(ctor.getModifiers())) throw new IllegalStateException("Constructor not public: " + fqn); Type guard
static boolean isPubliclyInstantiable(Class<?> c) {
try {
return Modifier.isPublic(c.getModifiers())
&& Modifier.isPublic(c.getDeclaredConstructor().getModifiers());
} catch (NoSuchMethodException e) { return false; }
} Try / catch
try {
return PluginRegistry.getInstance().loadClass(plugin, pluginClass);
} catch (KettlePluginException e) {
if (e.getMessage().contains("Illegal access")) {
log.error("Make plugin class and no-arg ctor public; check JPMS --add-opens on JDK 9+", e);
}
throw e;
} Prevention
- Declare plugin classes and constructors public; avoid package-private/nested implementations.
- Don't enforce singletons via private constructors on classes Kettle instantiates.
- After JDK upgrades, test plugin loading; add --add-opens for encapsulated packages.
- Review access modifiers in code review for any class referenced in plugin metadata.
When it happens
Trigger: cl.newInstance() throws IllegalAccessException because the plugin class or its constructor is private/protected/package-private, or the class is in a non-exported package (Java 9+ modules / sealed packages) relative to PluginRegistry's loader context.
Common situations: Plugin implementation class declared package-private or nested (non-public static class); constructor made private by a singleton pattern; strong encapsulation (JPMS) blocks reflective access after a JDK upgrade.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- PLUGINREGISTRY004
- Error executing UserDefinedJavaClass.getFields():
- KettleMissingPluginsException( getErrorMessage(…
- KettleMissingPluginsException( getErrorMessage(…
- No ID specified for plugin with class
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/7e19617fe4424c31.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/plugins/PluginRegistry.java:529
Class<? extends T> cl;
if ( plugin.isNativePlugin() ) {
cl = (Class<? extends T>) Class.forName( className );
} else {
ClassLoader ucl = getClassLoader( plugin );
// Load the class.
cl = (Class<? extends T>) ucl.loadClass( className );
}
return cl.newInstance();
} catch ( ClassNotFoundException e ) {
throw new KettlePluginException( BaseMessages.getString(
PKG, "PluginRegistry.RuntimeError.ClassNotFound.PLUGINREGISTRY003" ), e );
} catch ( InstantiationException e ) {
throw new KettlePluginException( BaseMessages.getString(
PKG, "PluginRegistry.RuntimeError.UnableToInstantiateClass.PLUGINREGISTRY004" ), e );
} catch ( IllegalAccessException e ) {
throw new KettlePluginException( BaseMessages.getString(
PKG, "PluginRegistry.RuntimeError.IllegalAccessToClass.PLUGINREGISTRY005" ), e );
} catch ( Throwable e ) {
e.printStackTrace();
throw new KettlePluginException( BaseMessages.getString(
PKG, "PluginRegistry.RuntimeError.UnExpectedErrorLoadingClass.PLUGINREGISTRY007" ), e );
}
}
}
/**
* Add a PluginType to be managed by the registry
*
* @param type
*/
public static void addPluginType( PluginTypeInterface type ) {
pluginTypes.add( type );
}
View on GitHub (pinned to f3058517a1)