pentaho/pentaho-kettle · error · KettlePluginException

PLUGINREGISTRY008

PLUGINREGISTRY008

Error message

Error creating class loader

What it means

KettlePluginException with code PLUGINREGISTRY008 thrown by PluginRegistry.createClassLoader as the catch-all for any unexpected Throwable while building the plugin's URLClassLoader. Unlike PLUGINREGISTRY006 it is not limited to MalformedURLException - any error during classloader assembly (e.g. SecurityException, NPE on a null jar path) lands here after being printed to stderr.

Solutions

  1. Read the stderr stack trace printed before the exception and the wrapped cause to identify the real failure
  2. Ensure the jarFiles list passed to createClassLoader contains no null entries and the plugin folder is non-null
  3. Check for SecurityManager / container policies blocking ClassLoader creation
  4. Verify plugin metadata (plugin.xml / annotation) is intact for the plugin being loaded

Example fix

// before
ClassLoader ucl = PluginRegistry.init().createClassLoader(plugin, null); // plugin folder may be null
// after
if ( plugin.getPluginDirectory() != null && new File( plugin.getPluginDirectory() ).exists() ) {
  ClassLoader ucl = PluginRegistry.init().createClassLoader( plugin, null );
}
Defensive patterns

Strategy: try-catch

Validate before calling

PluginInterface plugin = ...;
boolean ok = plugin != null
  && plugin.getPluginDirectory() != null
  && new java.io.File( plugin.getPluginDirectory().getPath() ).exists();
if ( !ok ) throw new IllegalStateException("plugin or its folder is not resolvable");

Type guard

static boolean canCreateClassLoader(PluginInterface p) {
  return p != null && p.getPluginDirectory() != null && p.getJarFiles() != null;
}

Try / catch

try {
  ClassLoader ucl = registry.createClassLoader(plugin, null);
} catch ( KettlePluginException e ) {
  if ( e.getMessage().contains("PLUGINREGISTRY008") ) {
    log.error("Unexpected classloader failure for plugin " + plugin.getName(), e.getCause());
  }
}

Prevention

When it happens

Trigger: Calling PluginRegistry.createClassLoader when anything other than URL parsing fails: a null entry in the jarFiles list, a SecurityManager denying classloader creation, or an unexpected runtime exception while resolving the plugin folder URL.

Common situations: Null or empty jar file paths passed programmatically; running under a restrictive security policy or container that forbids new classloaders; corrupted plugin registration metadata producing NPEs; plugin API version mismatch causing registry state surprises.

Related errors


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

Appendix: source

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

                    inverseClassLoaderLookup.computeIfAbsent( ucl, k -> new HashSet<>() ).add( plugin );
                  }
                }
              }
            }
          }
        } finally {
          lock.writeLock().unlock();
        }

        // Load the class.
        return ucl;
      }
    } catch ( MalformedURLException e ) {
      throw new KettlePluginException( BaseMessages.getString(
          PKG, "PluginRegistry.RuntimeError.MalformedURL.PLUGINREGISTRY006" ), e );
    } catch ( Throwable e ) {
      e.printStackTrace();
      throw new KettlePluginException( BaseMessages.getString(
          PKG, "PluginRegistry.RuntimeError.UnExpectedCreatingClassLoader.PLUGINREGISTRY008" ), e );
    }
  }

  /**
   * Allows the tracking of plugins as they come and go.
   *
   * @param typeToTrack extension of PluginTypeInterface to track.
   * @param listener    receives notification when a plugin of the specified type is added/removed/modified
   * @param <T>         extension of PluginTypeInterface
   */
  public <T extends PluginTypeInterface> void addPluginListener( Class<T> typeToTrack, PluginTypeListener listener ) {
    lock.writeLock().lock();
    try {
      Set<PluginTypeListener> list = listeners.computeIfAbsent( typeToTrack, k -> new HashSet<>() );
      list.add( listener );
    } finally {
      lock.writeLock().unlock();

View on GitHub (pinned to f3058517a1)