pentaho/pentaho-kettle · error · KettleXMLException

RulesMeta.Error.LoadFromXML

RulesMeta.Error.LoadFromXML

Error message

RulesMeta.Error.LoadFromXML

What it means

RulesExecutorMeta.loadXML() deserializes the Rules Executor step configuration from the transformation's .ktr XML: it reads the <fields> result-column entries (creating a ValueMetaInterface per field via ValueMetaFactory.createValueMeta) and the rule-file / rule-definition tags. Any exception in this block is wrapped in a KettleXMLException with the i18n message "RulesMeta.Error.LoadFromXML", meaning the persisted step definition could not be loaded.

Solutions

  1. Inspect the KettleXMLException's cause (getCause()) to find the underlying failure (usually the unmapped value-type name or an NPE).
  2. Open the .ktr in a text editor and validate each <field>'s column-name/column-type inside the step's <fields> block against valid PDI value types.
  3. Delete and re-add the Rules Executor step in Spoon, reconfigure, and re-save to regenerate clean XML.
  4. Restore the transformation from backup or version control if the file is corrupted/truncated.
  5. If upgrading PDI, use the documented migration path rather than reusing old XML directly.

Example fix

<!-- before: missing <fields> wrapper breaks loadXML -->
<field>
  <column-name>result</column-name>
  <column-type>String</column-type>
</field>

<!-- after -->
<fields>
  <field>
    <column-name>result</column-name>
    <column-type>String</column-type>
  </field>
</fields>
Defensive patterns

Strategy: try-catch

Validate before calling

// Before loading from XML, check required structure and types
Node fields = XMLHandler.getSubNode(stepnode, "fields");
if (fields == null) throw new IllegalArgumentException("Rules Executor XML missing <fields> node");
for (int i = 0; i < XMLHandler.countNodes(fields, "field"); i++) {
  Node f = XMLHandler.getSubNodeByNr(fields, "field", i);
  String type = XMLHandler.getTagValue(f, "column-type");
  if (type == null || ValueMeta.getType(type) < 0)
    throw new IllegalArgumentException("invalid column-type: " + type);
}

Type guard

boolean isLoadableRulesExecutorNode(Node stepnode) {
  Node fields = XMLHandler.getSubNode(stepnode, "fields");
  if (fields == null) return false;
  int n = XMLHandler.countNodes(fields, "field");
  for (int i = 0; i < n; i++) {
    String type = XMLHandler.getTagValue(XMLHandler.getSubNodeByNr(fields, "field", i), "column-type");
    if (type == null || ValueMeta.getType(type) < 0) return false;
  }
  return true;
}

Try / catch

try {
  meta.loadXML(stepnode, databases, metaStore);
} catch (KettleXMLException e) {
  logError("Rules Executor step XML failed to load: " + e.getCause(), e);
  throw new KettleXMLException("Invalid Rules Executor XML — verify <fields> block and column-type values", e);
}

Prevention

When it happens

Trigger: Loading a Rules Executor step from XML when the <fields>/<field> structure is malformed or missing (NPE in getSubNode/countNodes), a column-type value that ValueMeta.getType()/ValueMetaFactory cannot resolve, createValueMeta throwing for an unsupported type code, or XMLHandler failing while reading rule-file/rule-definition tags.

Common situations: Transformation saved by a different PDI version with a changed XML schema; hand-edited .ktr with an invalid column-type name; corrupted/truncated transformation file; XML copied between transformations with missing nodes.

Related errors


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

Appendix: source

Thrown at plugins/drools/core/src/main/java/org/pentaho/di/trans/steps/rules/RulesExecutorMeta.java:153

    try {
      Node fields = XMLHandler.getSubNode( stepnode, StorageKeys.NODE_FIELDS.toString() );
      int nrfields = XMLHandler.countNodes( fields, StorageKeys.SUBNODE_FIELD.toString() );

      ValueMetaInterface vm = null;
      for ( int i = 0; i < nrfields; i++ ) {
        Node fnode = XMLHandler.getSubNodeByNr( fields, StorageKeys.SUBNODE_FIELD.toString(), i );

        String name = XMLHandler.getTagValue( fnode, StorageKeys.COLUMN_NAME.toString() );
        int type = ValueMeta.getType( XMLHandler.getTagValue( fnode, StorageKeys.COLUMN_TYPE.toString() ) );

        vm = ValueMetaFactory.createValueMeta( name, type );
        getRuleResultColumns().add( vm );
      }

      setRuleFile( XMLHandler.getTagValue( stepnode, StorageKeys.RULE_FILE.toString() ) );
      setRuleDefinition( XMLHandler.getTagValue( stepnode, StorageKeys.RULE_DEFINITION.toString() ) );
    } catch ( Exception e ) {
      throw new KettleXMLException( BaseMessages.getString( PKG, "RulesMeta.Error.LoadFromXML" ), e );
    }
  }

  @Override
  public String getXML() {
    StringBuffer retval = new StringBuffer( 300 );

    retval.append( "    <" + StorageKeys.NODE_FIELDS + ">" ).append( Const.CR );
    for ( int i = 0; i < ruleResultColumns.size(); i++ ) {
      retval.append( "      <" + StorageKeys.SUBNODE_FIELD + ">" ).append( Const.CR );
      retval.append( "        " ).append(
        XMLHandler.addTagValue( StorageKeys.COLUMN_NAME.toString(), ruleResultColumns.get( i ).getName() ) );
      retval.append( "        " ).append(
        XMLHandler.addTagValue( StorageKeys.COLUMN_TYPE.toString(), ruleResultColumns.get( i ).getTypeDesc() ) );
      retval.append( "      </" + StorageKeys.SUBNODE_FIELD + ">" ).append( Const.CR );
    }
    retval.append( "    </" + StorageKeys.NODE_FIELDS + ">" ).append( Const.CR );
    retval.append( "    " ).append( XMLHandler.addTagValue( StorageKeys.RULE_FILE.toString(), getRuleFile() ) );

View on GitHub (pinned to f3058517a1)