pentaho/pentaho-kettle · error · KettleException
ScriptValuesMetaMod.Exception.UnableToLoadAdditionalClass
Error message
ScriptValuesMetaMod.Exception.UnableToLoadAdditionalClass
What it means
LoadAdditionalClass wraps any failure to load a class from an additional ScriptValues_mod JAR with a KettleURLClassLoader into a KettleException with this message. It is the lower-level cause of the additional-classes load failure: the JAR URL could not be opened or loadClass could not find/define the requested class. The root cause is attached.
Solutions
- Read the nested cause: ClassNotFoundException -> fix class name/deploy JAR; UnsupportedClassVersionError -> rebuild or run a newer JDK
- Verify the class name (fully qualified, no typo, correct case) configured for the additional class
- Ensure the JAR exists and is readable at the given path and is a valid ZIP/JAR (unzip -t)
- Bundle or add to the classpath any libraries the additional class depends on
- Deploy identical JARs to every node (clustered execution)
Example fix
// before
Class<?> toRun = kl.loadClass("com.x.Helperr"); // ClassNotFoundException
// after: check before wrapping the jar
File f = new File(jarPath);
if (!f.canRead()) throw new KettleException("Missing additional jar: " + jarPath);
Class<?> toRun = kl.loadClass("com.x.Helper"); // exact FQN Defensive patterns
Strategy: try-catch
Validate before calling
try (JarFile jf = new JarFile(jarPath)) {
if (jf.getJarEntry(className.replace('.', '/') + ".class") == null)
throw new KettleException("Class " + className + " not in " + jarPath);
} Try / catch
try {
Class<?> c = new KettleURLClassLoader(new URL[]{ new URL(jarPath) }, cl).loadClass(className);
} catch (ClassNotFoundException cnfe) {
throw new KettleException("Class " + className + " not found in " + jarPath
+ " — check FQN spelling and JAR deployment", cnfe);
} catch (IOException ioe) {
throw new KettleException("Cannot open JAR " + jarPath, ioe);
} Prevention
- Use fully qualified, case-correct class names in step configuration
- Verify JAR integrity (unzip -t) after copying between environments
- Match the compile-time target JDK to the runtime JDK
- Ship transitive dependencies inside the additional JAR or on the plugin classpath
- Deploy identical JAR sets to all cluster nodes
When it happens
Trigger: new URL(jarPath) fails or the JAR file does not exist/is unreadable; kl.loadClass(strClassName) throws ClassNotFoundException because the class is absent from the JAR or the class name is misspelled; JAR is corrupt or compiled for an incompatible class file version; linkage errors (NoClassDefFoundError/LinkageError) for missing transitive dependencies.
Common situations: Typo in class name in the step configuration; JAR built with a newer JDK than the runtime; additional class references libraries not on the classpath (transitive dependency missing); JAR not deployed on a cluster node.
Related errors
- ScriptMeta.Exception.UnableToLoadAdditionalClass
- ScriptValuesMetaMod.Exception.UnableToParseXMLforAdditionalC…
- Could not create ValueMetaInterface
- ERROR_0016_COULD_NOT_GET_REPOSITORY_INSTANCE
- Error calling extension point at end of transformation
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/03c688488579bc01.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/scriptvalues_mod/ScriptValuesMetaMod.java:1006
}
} catch ( Exception e ) {
throw new KettleException( BaseMessages.getString(
PKG, "ScriptValuesMetaMod.Exception.UnableToParseXMLforAdditionalClasses" ), e );
}
}
private static Class<?> LoadAdditionalClass( String strJar, String strClassName ) throws KettleException {
try {
Thread t = Thread.currentThread();
ClassLoader cl = t.getContextClassLoader();
URL u = new URL( "jar:file:" + strJar + "!/" );
// We never know what else the script wants to load with the class loader, so lets not close it just like that.
@SuppressWarnings( "resource" )
KettleURLClassLoader kl = new KettleURLClassLoader( new URL[] { u }, cl );
Class<?> toRun = kl.loadClass( strClassName );
return toRun;
} catch ( Exception e ) {
throw new KettleException( BaseMessages.getString(
PKG, "ScriptValuesMetaMod.Exception.UnableToLoadAdditionalClass" ), e );
}
}
public ScriptValuesAddClasses[] getAddClasses() {
return additionalClasses;
}
/**
* @return the compatible
*/
public boolean isCompatible() {
return compatible;
}
/**
* @param compatible
* the compatible to setView on GitHub (pinned to f3058517a1)