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

  1. Make the plugin class public and give it a public no-argument constructor.
  2. Move nested plugin classes out to top-level public classes.
  3. Remove private constructors on the class Kettle must instantiate (use init()/lifecycle hooks instead of singleton enforcement).
  4. 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

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


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)