pentaho/pentaho-kettle · error · KettleXMLException
Unable to load step info from XML
Error message
Unable to load step info from XML
What it means
KettleXMLException thrown by RowGeneratorMeta.readData when any exception occurs while parsing the step's XML <step> node attributes (fields, limit, never_ending, interval_in_ms, row_time_field, last_time_field). loadXML calls readData during transformation deserialization, so a malformed or unexpectedly shaped .ktr file surfaces as this wrapped error.
Solutions
- Open the .ktr in a text editor and verify the RowGenerator step's XML block is well-formed and contains the expected tags (fields, limit, never_ending, interval_in_ms, row_time_field, last_time_field).
- Read the wrapped cause 'e' in the stack trace to find the exact XML parse failure and fix that line.
- Recreate the Row Generator step in Spoon and re-save the transformation to regenerate clean XML.
- Confirm the file was produced by a compatible Kettle/Pentaho version; migrate via Spoon rather than manual edits.
Example fix
// before: hand-edited XML missing closing tag <fields><field>...</fields> // after: well-formed step XML <fields><field><name>id</name><type>Integer</type></field></fields>
Defensive patterns
Strategy: try-catch
Validate before calling
// Before loading, validate XML well-formedness
DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File("trans.ktr")); Type guard
Node stepNode = XMLHandler.getSubNode(stepnode, "fields");
if (stepNode == null) { throw new IllegalArgumentException("RowGenerator step XML missing <fields> node"); } Try / catch
try {
transMeta = new TransMeta("trans.ktr");
} catch (KettleXMLException e) {
log.error("Failed to parse transformation XML: {}", e.getCause(), e);
// fall back to a known-good copy of the file
} Prevention
- Never hand-edit .ktr files; edit in Spoon and re-save.
- Run xmllint --noout on generated XML before loading.
- Keep transformations under version control to restore a known-good copy.
- Always log e.getCause() to see the underlying XMLHandler failure.
When it happens
Trigger: loadXML(stepnode, ...) is invoked while loading a transformation from XML and XMLHandler.getTagValue or another call inside readData throws (malformed XML, missing node structure, unexpected null/parse failure in a tag value).
Common situations: Opening a hand-edited or truncated .ktr file; a .ktr produced by a different Pentaho version with different XML attributes; copy-pasting a step XML snippet that is not nested under the expected <step> node; corrupted file transfer.
Related errors
- SampleRowsMeta.Exception.UnableToReadStepInfo
- Unable to load step info from XML
- ColumnExistsMeta.Exception.UnableToReadStepInfo
- CreditCardValidatorMeta.Exception.UnableToReadStepInfo
- CubeOutputMeta.Exception.UnableToLoadStepInfo
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/f8d7e3446e67ba81.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/rowgenerator/RowGeneratorMeta.java:165
slength = XMLHandler.getTagValue( fnode, "length" );
sprecision = XMLHandler.getTagValue( fnode, "precision" );
fieldLength[i] = Const.toInt( slength, -1 );
fieldPrecision[i] = Const.toInt( sprecision, -1 );
String emptyString = XMLHandler.getTagValue( fnode, "set_empty_string" );
setEmptyString[i] = !Utils.isEmpty( emptyString ) && "Y".equalsIgnoreCase( emptyString );
}
// Is there a limit on the number of rows we process?
rowLimit = XMLHandler.getTagValue( stepnode, "limit" );
neverEnding = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "never_ending" ) );
intervalInMs = XMLHandler.getTagValue( stepnode, "interval_in_ms" );
rowTimeField = XMLHandler.getTagValue( stepnode, "row_time_field" );
lastTimeField = XMLHandler.getTagValue( stepnode, "last_time_field" );
} catch ( Exception e ) {
throw new KettleXMLException( "Unable to load step info from XML", e );
}
}
public void setDefault() {
int i, nrfields = 0;
allocate( nrfields );
DecimalFormat decimalFormat = new DecimalFormat();
for ( i = 0; i < nrfields; i++ ) {
fieldName[i] = "field" + i;
fieldType[i] = "Number";
fieldFormat[i] = "\u00A40,000,000.00;\u00A4-0,000,000.00";
fieldLength[i] = 9;
fieldPrecision[i] = 2;
currency[i] = decimalFormat.getDecimalFormatSymbols().getCurrencySymbol();
decimal[i] = new String( new char[] { decimalFormat.getDecimalFormatSymbols().getDecimalSeparator() } );View on GitHub (pinned to f3058517a1)