pentaho/pentaho-kettle · error · KettleXMLException
Unable to load step info from XML
Error message
Unable to load step info from XML
What it means
SalesforceInsertMeta.readData() wraps the whole XML deserialization of the step's configuration in a try/catch and rethrows any exception as a KettleXMLException with the generic message 'Unable to load step info from XML'. It means the <step> XML node for a Salesforce Insert step could not be parsed — typically a malformed tag, missing attribute, or an unexpected value when the transformation .ktr file was read. The original cause is chained as the 'cause' of the KettleXMLException.
Solutions
- Read the chained cause (e.getCause()) of the KettleXMLException — it names the exact tag/value that failed to parse.
- Open the .ktr in a text editor and locate the Salesforce Insert <step> XML block; fix malformed/missing tags or remove the step and re-add it in Spoon.
- Regenerate the transformation in the same PDI version that will run it (avoid round-tripping across major versions).
- If version migration is required, export/import via Spoon rather than editing XML directly.
Example fix
// before: hand-edited step XML <rollbackAllChangesOnError>yes</rollbackAllChangesOnError> // after: parser expects Y/N comparison via "Y".equalsIgnoreCase(...) <rollbackAllChangesOnError>Y</rollbackAllChangesOnError>
Defensive patterns
Strategy: try-catch
Validate before calling
// Validate the step XML block before loading
org.w3c.dom.NodeList steps = doc.getElementsByTagName("step");
for (int i = 0; i < steps.getLength(); i++) {
Node n = steps.item(i);
if (XMLHandler.getTagValue(n, "type").equals("SalesforceInsert")
&& XMLHandler.getTagValue(n, "connection") == null) {
throw new IllegalArgumentException("SalesforceInsert step XML is incomplete");
}
} Try / catch
try {
transMeta = new TransMeta(ktrFile);
} catch (KettleXMLException e) {
log.error("Step XML load failed: {}", e.getCause() != null ? e.getCause().getMessage() : e.getMessage(), e);
throw e;
} Prevention
- Never hand-edit .ktr XML; make step changes in Spoon.
- Pin one PDI version for authoring and execution.
- Keep .ktr files in version control and review merge conflicts around step blocks.
- Always log the chained cause when catching KettleXMLException.
When it happens
Trigger: Calling loadXML(Node stepnode, ...) on a SalesforceInsertMeta whose XML node is corrupt: XMLHandler.getTagValue() throws or returns data that fails parsing, e.g. during TransMeta.loadXML of a .ktr file containing a salesforce-insert step whose XML block is hand-edited, truncated, or produced by an incompatible PDI version.
Common situations: Opening a transformation edited by hand or by another tool; upgrading PDI and loading a .ktr written by an older/newer plugin version; a copied XML snippet pasted into the .ktr with missing or malformed child tags like rollbackAllChangesOnError.
Related errors
- Unable to load step info from XML
- MergeJoinMeta.Exception.UnableToLoadStepInfo
- MergeRowsMeta.Exception.UnableToLoadStepInfo
- AccessInputMeta.Exception.ErrorReadingRepository
- AggregateRowsMeta.Exception.UnexpectedErrorWhileReadingStepInfo
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/5263041b0e0e112b.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/salesforce/core/src/main/java/org/pentaho/di/trans/steps/salesforceinsert/SalesforceInsertMeta.java:240
updateStream[i] = updateLookup[i]; // default: the same name!
}
String updateValue = XMLHandler.getTagValue( fnode, "useExternalId" );
if ( updateValue == null ) {
// default FALSE
useExternalId[i] = Boolean.FALSE;
} else {
if ( updateValue.equalsIgnoreCase( "Y" ) ) {
useExternalId[i] = Boolean.TRUE;
} else {
useExternalId[i] = Boolean.FALSE;
}
}
}
setRollbackAllChangesOnError(
"Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "rollbackAllChangesOnError" ) ) );
} catch ( Exception e ) {
throw new KettleXMLException( "Unable to load step info from XML", e );
}
}
public void allocate( int nrvalues ) {
setUpdateLookup( new String[nrvalues] );
setUpdateStream( new String[nrvalues] );
setUseExternalId( new Boolean[nrvalues] );
}
public void setDefault() {
super.setDefault();
setBatchSize( "10" );
setSalesforceIDFieldName( "Id" );
allocate( 0 );
setRollbackAllChangesOnError( false );
}View on GitHub (pinned to f3058517a1)