pentaho/pentaho-kettle · error · KettleXMLException
StringOperationsMeta.Exception.UnableToReadStepInfoFromXML
Error message
StringOperationsMeta.Exception.UnableToReadStepInfoFromXML
What it means
StringOperationsMeta throws this KettleXMLException in readData() (called from loadXML) when parsing the step's XML definition fails unexpectedly. The wrapper keeps the original exception as the cause. The step cannot be loaded from the .ktr until the XML structure is corrected.
Solutions
- Inspect the wrapped cause to pinpoint the malformed XML element
- Repair the <fields><field> section of the step XML so each field node has the expected tags
- Regenerate the step XML by re-saving it from Spoon
- Restore the .ktr from version control or backup
Example fix
// before <field><field_in>a</field_in> <!-- missing required child tags --> // after <field><field_in>a</field_in><field_out>b</field_out><trim_type>none</trim_type><mask_xml></mask_xml><digits>none</digits><remove_special_characters>none</remove_special_characters></field>
Defensive patterns
Strategy: try-catch
Validate before calling
// check the fields node before loadXML
Node fieldsNode = XMLHandler.getSubNode(stepnode, "fields");
if (fieldsNode == null) {
logBasic("No fields node; step will use defaults");
}
for (int i = 0; fieldsNode != null && i < XMLHandler.countNodes(fieldsNode, "field"); i++) {
Node f = XMLHandler.getSubNodeByNr(fieldsNode, "field", i);
if (XMLHandler.getTagValue(f, "field_in") == null) {
throw new IllegalArgumentException("Missing field_in at field #" + i);
}
} Type guard
boolean isParsableFieldsNode(Node stepnode) {
Node fields = XMLHandler.getSubNode(stepnode, "fields");
return fields == null || XMLHandler.countNodes(fields, "field") >= 0;
} Try / catch
try {
meta.loadXML(stepnode, databases, context);
} catch (KettleXMLException e) {
logError("Bad StringOperations XML: " + e.getCause(), e);
meta.setDefault(); // degrade gracefully
} Prevention
- Edit step XML only through Spoon, never manually
- Validate .ktr XML well-formedness before loading
- Restore corrupted files from version control or backups
- Compare against a known-good step XML when upgrading PDI versions
When it happens
Trigger: Calling loadXML() when XMLHandler.getTagValue(fnode, ...) or the field-array setup throws — malformed <fields>/<field> nodes, unexpected null elements, or DOM errors while reading field_in/mask_xml/digits/remove_special_characters tags.
Common situations: Hand-edited or truncated .ktr XML; XML generated by a different PDI version with a diverged schema; corrupted file after a bad merge or transfer.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- StringCutMeta.Exception.UnableToReadStepInfoFromXML
- FlattenerMeta.Exception.UnableToLoadStepInfoFromXML
- SwitchCaseMeta.Exception..UnableToLoadStepInfoFromXML
- Unable to load step info from XML
- Unable to load step info from XML
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/5e5ef734fa19fde9.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/stringoperations/StringOperationsMeta.java:422
for ( int i = 0; i < nrkeys; i++ ) {
Node fnode = XMLHandler.getSubNodeByNr( lookup, "field", i );
fieldInStream[i] = Const.NVL( XMLHandler.getTagValue( fnode, "in_stream_name" ), "" );
fieldOutStream[i] = Const.NVL( XMLHandler.getTagValue( fnode, "out_stream_name" ), "" );
trimType[i] = Const.NVL( XMLHandler.getTagValue( fnode, "trim_type" ), "" );
lowerUpper[i] = Const.NVL( XMLHandler.getTagValue( fnode, "lower_upper" ), "" );
padding_type[i] = Const.NVL( XMLHandler.getTagValue( fnode, "padding_type" ), "" );
padChar[i] = Const.NVL( XMLHandler.getTagValue( fnode, "pad_char" ), "" );
padLen[i] = Const.NVL( XMLHandler.getTagValue( fnode, "pad_len" ), "" );
initCap[i] = Const.NVL( XMLHandler.getTagValue( fnode, "init_cap" ), "" );
maskXML[i] = Const.NVL( XMLHandler.getTagValue( fnode, "mask_xml" ), "" );
digits[i] = Const.NVL( XMLHandler.getTagValue( fnode, "digits" ), "" );
remove_special_characters[i] = Const.NVL( XMLHandler.getTagValue( fnode, "remove_special_characters" ), "" );
}
} catch ( Exception e ) {
throw new KettleXMLException( BaseMessages.getString(
PKG, "StringOperationsMeta.Exception.UnableToReadStepInfoFromXML" ), e );
}
}
@Override
public void setDefault() {
fieldInStream = null;
fieldOutStream = null;
int nrkeys = 0;
allocate( nrkeys );
}
@Override
public String getXML() {
StringBuilder retval = new StringBuilder( 500 );
View on GitHub (pinned to f3058517a1)