pentaho/pentaho-kettle · error · RuntimeException

Error creating plugin class

Error message

Error creating plugin class

What it means

SupplementalPlugin.loadClass resolves a registered supplier/callable for the plugin class and invokes it to produce the plugin instance; any exception during that factory call is wrapped as RuntimeException containing a KettlePluginException 'Error creating plugin class'. It signals the plugin's factory (usually a no-arg constructor or lambda registered in factoryMap) failed.

Solutions

  1. Read the wrapped KettlePluginException cause to see why the plugin's constructor/factory failed
  2. Initialize the Kettle environment (KettleEnvironment.init()) before loading supplemental plugins
  3. Ensure the plugin class has a public no-arg constructor and all its dependencies are on the classpath
  4. Unwrap the RuntimeException: new KettlePluginException(...) is the cause, and its cause is the original failure

Example fix

// before
MyStepPlugin plugin = supplementalPlugin.loadClass(); // env not initialized
// after
KettleEnvironment.init();
MyStepPlugin plugin = supplementalPlugin.loadClass();
Defensive patterns

Strategy: try-catch

Validate before calling

KettleEnvironment.init(); // ensure environment is ready before loadClass
Object factory = supplementalPlugin.getClass() != null; // plugin class resolvable
Class.forName(pluginClassName);

Type guard

static boolean canInstantiate(String cls) {
  try { Class.forName(cls).getConstructor().newInstance(); return true; }
  catch ( Exception e ) { return false; }
}

Try / catch

try {
  T plugin = supplementalPlugin.loadClass();
} catch ( RuntimeException e ) {
  // cause is KettlePluginException, whose cause is the factory failure
  Throwable root = e.getCause() != null ? e.getCause().getCause() : e;
  log.error("Supplemental plugin factory failed", root);
}

Prevention

When it happens

Trigger: Calling SupplementalPlugin.loadClass() when the Callable registered in factoryMap for pluginClass throws - typically the plugin class's constructor throws, or no mapping exists and the code path assumes one (resulting in NPE wrapped here).

Common situations: Supplemental plugin's constructor depends on an uninitialized Kettle environment (e.g. KettleLogStore or properties not initialized yet); plugin class changed between versions so the registered factory no longer matches; plugin class throws due to missing dependencies on the classpath.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/8d5afbb7c62d1de8. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/pentaho/di/core/plugins/SupplementalPlugin.java:50

  private String id;

  public SupplementalPlugin( Class<? extends PluginTypeInterface> pluginClass, String id ) {
    super( new String[] { id }, pluginClass, null,
      "", id, id, "", false, false, Collections.emptyMap(), Collections.emptyList(), "",
      null );
    this.pluginClass = pluginClass;
    this.id = id;
  }

  @Override public <T> T loadClass( Class<T> pluginClass ) {
    if ( !factoryMap.containsKey( pluginClass ) ) {
      return null;
    }

    try {
      return (T) factoryMap.get( pluginClass ).call();
    } catch ( Exception e ) {
      throw new RuntimeException( new KettlePluginException( "Error creating plugin class", e ) );
    }
  }

  @Override public ClassLoader getClassLoader() {
    return getClass().getClassLoader();
  }

  public <T> void addFactory( Class<T> tClass, Callable<T> callable ) {
    factoryMap.put( tClass, callable );
  }

}

View on GitHub (pinned to f3058517a1)