pentaho/pentaho-kettle · error · KettleXMLException

JoinRowsMeta.Exception.UnableToReadStepInfoFromXML

JoinRowsMeta.Exception.UnableToReadStepInfoFromXML

Error message

JoinRowsMeta.Exception.UnableToReadStepInfoFromXML

What it means

JoinRowsMeta.readData() throws this KettleXMLException when parsing the Join Rows step's XML definition fails while loading a transformation from a .ktr file. Any exception raised while reading the step attributes (prefix/suffix/main step, optional Condition node, etc.) is wrapped in this error. It indicates the XML fragment for this step is missing required nodes or is structurally invalid.

Solutions

  1. Validate/open the .ktr in Spoon and re-create or re-save the JoinRows step to regenerate correct XML.
  2. Diff the step's XML block against a known-good JoinRows definition; restore missing nodes (prefix, suffix, mainstep, condition).
  3. Confirm the file was produced by a compatible PDI version; upgrade/downgrade to match the generating version.
  4. Restore the transformation file from version control or backup if it is truncated/corrupted.

Example fix

// before ( hand-edited, missing condition node attrs )
<step><name>Join</name><type>JoinRows</type><prefix>join_</prefix></step>

// after ( re-saved by Spoon with all nodes )
<step>
  <name>Join</name><type>JoinRows</type>
  <prefix>join_</prefix><suffix>_data</suffix>
  <mainstep>MainStream</mainstep>
  <condition><operator>AND</operator>...</condition>
</step>
Defensive patterns

Strategy: try-catch

Validate before calling

Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse( new File( ktrPath ) );
NodeList steps = doc.getElementsByTagName( "step" );
for ( int i = 0; i < steps.getLength(); i++ ) {
  Element s = (Element) steps.item( i );
  if ( "JoinRows".equals( s.getElementsByTagName( "type" ).item( 0 ).getTextContent() )
       && s.getElementsByTagName( "prefix" ).getLength() == 0 ) {
    throw new IllegalStateException( "JoinRows step XML incomplete in " + ktrPath );
  }
}

Try / catch

try {
  transMeta = new TransMeta( ktrPath );
} catch ( KettleXMLException e ) {
  if ( e.getMessage() != null && e.getMessage().contains( "JoinRowsMeta" ) ) {
    throw new IllegalStateException( "JoinRows step XML invalid in " + ktrPath + "; re-save the step in Spoon", e );
  }
  throw e;
}

Prevention

When it happens

Trigger: loadXML -> readData with a <step type="JoinRows"> element lacking required child nodes (e.g. prefix, mainstep) or containing a malformed <condition> element that Condition's XML constructor cannot parse.

Common situations: Hand-editing a .ktr file and deleting/mis-nesting nodes; loading a transformation written by an incompatible PDI version whose JoinRows XML schema differs; truncated or corrupted .ktr after a bad checkout/transfer.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/joinrows/JoinRowsMeta.java:203

    try {
      directory = XMLHandler.getTagValue( stepnode, "directory" );
      prefix = XMLHandler.getTagValue( stepnode, "prefix" );
      cacheSize = Const.toInt( XMLHandler.getTagValue( stepnode, "cache_size" ), -1 );

      mainStepname = XMLHandler.getTagValue( stepnode, "main" );

      Node compare = XMLHandler.getSubNode( stepnode, "compare" );
      Node condnode = XMLHandler.getSubNode( compare, "condition" );

      // The new situation...
      if ( condnode != null ) {
        condition = new Condition( condnode );
      } else {
        condition = new Condition();
      }

    } catch ( Exception e ) {
      throw new KettleXMLException( BaseMessages.getString(
        PKG, "JoinRowsMeta.Exception.UnableToReadStepInfoFromXML" ), e );
    }
  }

  @Override
  public void setDefault() {
    directory = "%%java.io.tmpdir%%";
    prefix = "out";
    cacheSize = 500;

    mainStepname = null;
  }

  @Override
  public String getXML() throws KettleException {
    StringBuilder retval = new StringBuilder( 300 );

    retval.append( "      " ).append( XMLHandler.addTagValue( "directory", directory ) );

View on GitHub (pinned to f3058517a1)