pentaho/pentaho-kettle · error · KettlePluginException

PLUGINREGISTRY003

PLUGINREGISTRY003

Error message

Class not found

What it means

At the end of loadClass, the registry loads the class via the plugin's URLClassLoader (ucl.loadClass(className)) and instantiates it. A ClassNotFoundException is rethrown as KettlePluginException 'Class not found' (PLUGINREGISTRY003) with the original as cause — the plugin jar/folder does not contain the mapped class name.

Solutions

  1. Check the class name in the plugin annotation/plugin.xml against the actual FQN in the jar (javap or jar tf | grep <ClassName>).
  2. Run jar tf plugin.jar to confirm the class file exists at the expected path.
  3. Redeploy a complete plugin build; if dependencies are missing, add them to the plugin's lib folder.
  4. Verify the plugin folder's jars are the version matching the metadata (no stale duplicate jars).

Example fix

// before
@Step(id = "MyStep", classnamelist = {"com.acme.step.MyStepMeta"}) // actual: com.acme.step.MyStepMetaNew

// after
@Step(id = "MyStep", classnamelist = {"com.acme.step.MyStepMetaNew"})
Defensive patterns

Strategy: validation

Validate before calling

String fqn = "com.acme.MyStepMeta";
try {
  Class.forName(fqn, false, pluginClassLoader);
} catch (ClassNotFoundException e) {
  throw new IllegalStateException("Class not in plugin jar: " + fqn);
}

Try / catch

try {
  Object o = PluginRegistry.getInstance().loadClass(plugin, pluginClass);
} catch (KettlePluginException e) {
  if (e.getMessage().contains("Class not found")) {
    log.error("Mapped class missing from " + plugin.getName() + " jar; verify plugin.xml/annotation FQNs", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: ucl.loadClass(className) fails because the class named in the plugin's metadata (mainClassFolder/classMap entry) is absent from the plugin's jar/folder URLs — wrong class name, missing jar entry, or the jar wasn't added to the classloader.

Common situations: Package/refactor renamed the class but plugin.xml or annotation still lists the old FQN; incomplete plugin deployment (jar missing some classes); dependency classes referenced by the plugin are absent so a NoClassDefFoundError surfaces as lookup failure; class in a nested jar VFS can't open.

Related errors


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

Appendix: source

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

        throw new KettlePluginClassMapException( BaseMessages.getString( PKG,
            "PluginRegistry.RuntimeError.NoValidClassRequested.PLUGINREGISTRY002", plugin.getName(),
            pluginClass.getName() ) );
      }

      try {
        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
   *

View on GitHub (pinned to f3058517a1)