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
- Validate/open the .ktr in Spoon and re-create or re-save the JoinRows step to regenerate correct XML.
- Diff the step's XML block against a known-good JoinRows definition; restore missing nodes (prefix, suffix, mainstep, condition).
- Confirm the file was produced by a compatible PDI version; upgrade/downgrade to match the generating version.
- 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
- Never hand-edit .ktr XML; modify steps through Spoon and commit the re-saved file.
- Keep the PDI client version uniform across the team to avoid schema drift in step XML.
- Commit transformations to VCS so corrupted files can be restored.
- If merging .ktr files, merge at the transformation level in Spoon, not via text diffs.
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
- GetTableNamesMeta.Exception.UnableToReadStepInfo
- GPBulkLoaderMeta.Exception.UnableToReadStepInfoFromXML
- GPBulkLoaderMeta.Exception.UnableToReadStepInfoFromXML
- GPLoadMeta.Exception.UnableToReadStepInfoFromXML
- GroupByMeta.Exception.UnableToLoadStepInfoFromXML
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)