pentaho/pentaho-kettle · error · KettleException

ScriptValuesMetaMod.Exception.UnableToParseXMLforAdditionalC…

Error message

ScriptValuesMetaMod.Exception.UnableToParseXMLforAdditionalClasses

What it means

When building a ScriptValuesMod step from XML (constructor that reads additional script classes), any exception while loading the configured additional JARs/classes is wrapped in a KettleException with this message. It indicates the <add_classes> section of the step XML could not be turned into live additionalClasses objects. The root cause is attached.

Solutions

  1. Read the nested cause to identify the exact failure (FileNotFound vs ClassNotFoundException vs InstantiationError)
  2. Deploy the referenced additional JAR to <kettle-dir>/plugins/steps/ScriptValues_mod/ and verify strActPath resolves to the real Kettle home
  3. Check the class name stored in the step XML matches a class actually present in the JAR
  4. Ensure the additional class has a public no-argument constructor that does not throw
  5. Re-export the transformation XML after fixing the additional-classes configuration

Example fix

// before: class missing on this machine -> wrapped as UnableToParseXMLforAdditionalClasses
// <add_classes><jar>myhelper.jar</jar><class>com.x.Helper</class>...
// after: verify before loading
File jar = new File(strActPath + "/plugins/steps/ScriptValues_mod/myhelper.jar");
if (!jar.exists()) throw new KettleException("Deploy myhelper.jar to " + jar.getPath());
Defensive patterns

Strategy: validation

Validate before calling

File dir = new File(System.getProperty("KETTLE_HOME", "."), "plugins/steps/ScriptValues_mod");
for (String jar : configuredJars) {
  if (!new File(dir, jar).exists())
    throw new KettleException("Missing additional jar: " + jar + " in " + dir);
}

Try / catch

try {
  stepMeta = new StepMeta(xStepNode, transMeta);
} catch (KettleException e) {
  if (e.getMessage().contains("UnableToParseXMLforAdditionalClasses")) {
    logError("Additional classes load failed: " + e.getCause(), e);
    // deploy JARs and retry, or strip add_classes from the XML
  } else throw e;
}

Prevention

When it happens

Trigger: During XML deserialization of step metadata: the configured class path '<kettle-home>/plugins/steps/ScriptValues_mod/<jar>' does not exist or is unreadable, the JAR is corrupt, the class name is wrong/missing, Class.newInstance() fails (no public no-arg ctor, or constructor throws), or the XML structure is malformed.

Common situations: Transformation XML moved to a machine where the extra JAR was not deployed under plugins/steps/ScriptValues_mod/; typo in the additional class name; the additional class was compiled against a different JDK or its no-arg constructor changed; plugin folder renamed.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/scriptvalues_mod/ScriptValuesMetaMod.java:990

      Document dom = XMLHandler.loadXMLFile( DefaultBowl.getInstance(),
                                             strActPath + "/plugins/steps/ScriptValues_mod/plugin.xml" );
      Node stepnode = dom.getDocumentElement();
      Node libraries = XMLHandler.getSubNode( stepnode, "js_libraries" );
      int nbOfLibs = XMLHandler.countNodes( libraries, "js_lib" );
      additionalClasses = new ScriptValuesAddClasses[nbOfLibs];
      for ( int i = 0; i < nbOfLibs; i++ ) {
        Node fnode = XMLHandler.getSubNodeByNr( libraries, "js_lib", i );
        String strJarName = XMLHandler.getTagAttribute( fnode, "name" );
        String strClassName = XMLHandler.getTagAttribute( fnode, "classname" );
        String strJSName = XMLHandler.getTagAttribute( fnode, "js_name" );

        Class<?> addClass =
          LoadAdditionalClass( strActPath + "/plugins/steps/ScriptValues_mod/" + strJarName, strClassName );
        Object addObject = addClass.newInstance();
        additionalClasses[i] = new ScriptValuesAddClasses( addClass, addObject, strJSName );
      }
    } 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 );
    }

View on GitHub (pinned to f3058517a1)