pentaho/pentaho-kettle · error · KettlePluginException

Unable to get instance of plugin type

Error message

Unable to get instance of plugin type: ${pluginTypeClass}

What it means

KettlePluginException thrown by PluginRegistry.getPluginType when the plugin-type class cannot be instantiated via its static getInstance() method. The registry expects every PluginTypeInterface implementation to expose a no-arg static getInstance(); reflection failures (missing method, constructor throwing, illegal access, class not loadable) are wrapped here.

Solutions

  1. Add/fix the required public static getInstance() no-arg method on the plugin type class (e.g. public static MyPluginType getInstance() { return instance; })
  2. Verify the plugin type class is on the classpath and the fully-qualified name is correct
  3. Read the wrapped cause: NoSuchMethodException means missing getInstance, ExceptionInInitializerError means the singleton constructor threw
  4. Rebuild the plugin against the same Kettle/PDI version in use

Example fix

// before
class MyPluginType implements PluginTypeInterface { public MyPluginType() {...} } // no getInstance
// after
class MyPluginType implements PluginTypeInterface {
  private static final MyPluginType instance = new MyPluginType();
  public static MyPluginType getInstance() { return instance; }
}
Defensive patterns

Strategy: validation

Validate before calling

Class<?> t = MyPluginType.class;
boolean ok = PluginTypeInterface.class.isAssignableFrom(t);
try {
  t.getMethod("getInstance");
} catch ( NoSuchMethodException e ) {
  throw new IllegalStateException(t.getName() + " lacks static getInstance()");
}

Type guard

static boolean isValidPluginType(Class<? extends PluginTypeInterface> t) {
  try { t.getMethod("getInstance"); return true; }
  catch ( NoSuchMethodException e ) { return false; }
}

Try / catch

try {
  PluginTypeInterface type = PluginRegistry.init().getPluginType(MyPluginType.class);
} catch ( KettlePluginException e ) {
  // cause is NoSuchMethodException | ClassNotFoundException | InvocationTargetException
  log.error("Cannot instantiate plugin type: " + e.getCause(), e.getCause());
}

Prevention

When it happens

Trigger: Calling PluginRegistry.getPluginType(SomePluginType.class) when the class has no static getInstance() method, its classloader cannot load it (ClassNotFoundException inside invoke/lookup), getInstance() itself throws, or the class isn't accessible via reflection.

Common situations: Custom plugin type implemented without the required static getInstance() method; class name typo when registering/looking up the plugin type; plugin jar not on the classpath so the type class fails to load; old plugin type compiled against a different Kettle API version.

Related errors


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

Appendix: source

Thrown at core/src/main/java/org/pentaho/di/core/plugins/PluginRegistry.java:1043

      Map<PluginInterface, URLClassLoader> classLoaders =
        classLoaderMap.computeIfAbsent( plugin.getPluginType(), k -> new HashMap<>() );
      classLoaders.put( plugin, ucl );
    } finally {
      lock.writeLock().unlock();
    }
  }

  public PluginTypeInterface getPluginType( Class<? extends PluginTypeInterface> pluginTypeClass )
      throws KettlePluginException {
    try {
      // All these plugin type interfaces are singletons...
      // So we should call a static getInstance() method...
      //
      Method method = pluginTypeClass.getMethod( "getInstance", new Class<?>[0] );

      return (PluginTypeInterface) method.invoke( null, new Object[0] );
    } catch ( Exception e ) {
      throw new KettlePluginException( "Unable to get instance of plugin type: " + pluginTypeClass.getName(), e );
    }
  }

  public List<PluginInterface> findPluginsByFolder( URL folder ) {
    String path = folder.getPath();
    try {
      path = folder.toURI().normalize().getPath();
    } catch ( URISyntaxException e ) {
      log.logError( e.getLocalizedMessage(), e );
    }
    if ( path.endsWith( "/" ) ) {
      path = path.substring( 0, path.length() - 1 );
    }
    List<PluginInterface> result = new ArrayList<PluginInterface>();
    lock.readLock().lock();
    try {
      for ( Set<PluginInterface> typeInterfaces : pluginMap.values() ) {
        for ( PluginInterface plugin : typeInterfaces ) {

View on GitHub (pinned to f3058517a1)