pentaho/pentaho-kettle · error · KettlePluginException

PLUGINREGISTRY006

PLUGINREGISTRY006

Error message

Malformed URL

What it means

KettlePluginException thrown by PluginRegistry.createClassLoader when constructing the URLClassLoader for a plugin fails because one of the plugin's jar/lib URLs is malformed. The registry converts each plugin folder/jar path into java.net.URL objects; an invalid URL string (bad syntax, unescaped characters, invalid protocol) triggers MalformedURLException which is wrapped with code PLUGINREGISTRY006.

Solutions

  1. Fix the plugin path so it is a valid URL: escape spaces (%20) or use folder.toURI().toURL() instead of new URL(folderPath)
  2. Check the plugin folder/jar actually exists and the path in the plugin configuration is correct
  3. Move the plugin to a directory without spaces or special characters
  4. Inspect the wrapped MalformedURLException cause for the exact offending URL

Example fix

// before
URL url = new URL("file:/opt/pentaho/plugins/my plugin/lib/x.jar");
// after
URL url = new File("/opt/pentaho/plugins/my plugin/lib/x.jar").toURI().toURL();
Defensive patterns

Strategy: try-catch

Validate before calling

String p = "/opt/pentaho/plugins/my plugin";
java.io.File f = new java.io.File(p);
if ( !f.exists() ) throw new IllegalStateException("plugin folder missing: " + p);
java.net.URL url = f.toURI().toURL(); // never throws MalformedURLException for existing files

Type guard

static boolean isSafePluginPath(String p) {
  return p != null && !p.isEmpty() && new java.io.File(p).exists();
}

Try / catch

try {
  ClassLoader ucl = PluginRegistry.init().createClassLoader(plugin, null);
} catch ( KettlePluginException e ) {
  // e.getMessage() contains PLUGINREGISTRY006; getCause() is the MalformedURLException
  log.error("Bad plugin URL for " + plugin.getName() + ": " + e.getCause().getMessage());
}

Prevention

When it happens

Trigger: Calling PluginRegistry.createClassLoader (directly or via plugin initialization) when a plugin's jarFiles list or plugin folder yields a URL that java.net.URL cannot parse - e.g. a path with spaces or illegal characters not escaped, or an unsupported protocol scheme.

Common situations: Plugin installed in a directory whose name contains spaces or non-ASCII characters; manually configured plugin paths in kettle.properties or plugin.xml with typos; Windows-style paths passed as URLs; a plugin jar moved/deleted leaving a stale relative path.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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

Appendix: source

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

                      }
                    }
                    ucl = createClassLoader( plugin );
                    classLoaders.put( plugin, ucl ); // save for later use...
                    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 {

View on GitHub (pinned to f3058517a1)