pentaho/pentaho-kettle · error · KettleXMLException
Unable to load job entry of type 'sql' from XML node
Error message
Unable to load job entry of type 'sql' from XML node
What it means
KettleXMLException thrown by JobEntrySQL.loadXML when parsing a 'sql' job entry's XML node fails with a KettleException. It wraps parse errors (missing/broken nodes) encountered while reading attributes like SQL filename, connection, and sendOneStatement.
Solutions
- Open the .kjb file in an XML validator/editor and fix malformed markup around the SQL entry node.
- Re-export or re-save the job from Spoon to regenerate well-formed XML.
- Verify the entry node has the expected SQL entry tags (sql, connection, sqlFilename, etc.).
- Check the wrapped cause exception for the exact parse failure.
Example fix
// before
Node entryNode = XMLHandler.getSubNode(jobNode, "entry");
sqlEntry.loadXML(entryNode, databases, slaveServers, rep, metaStore);
// after
Node entryNode = XMLHandler.getSubNode(jobNode, "entry");
if (entryNode == null) {
throw new KettleXMLException("Missing <entry> node in job XML");
}
sqlEntry.loadXML(entryNode, databases, slaveServers, rep, metaStore); Defensive patterns
Strategy: validation
Validate before calling
Document document = XMLHandler.loadXMLFile(jobFile);
Node job = XMLHandler.getSubNode(document, KitchenConfiguration.JOB_TAG); // or "job"
Node entry = XMLHandler.getSubNode(job, "entry");
if (entry == null) throw new KettleXMLException("Job XML has no <entry> node");
Type guard
boolean isValidEntryNode(Node n) {
return n != null && XMLHandler.getSubNode(n, "type") != null;
} Try / catch
try {
sqlEntry.loadXML(entrynode, databases, slaveServers, rep, metaStore);
} catch (KettleXMLException e) {
logError("Malformed SQL entry XML: " + e.getCause(), e);
} Prevention
- Never hand-edit .kjb files without validating afterwards
- Transfer job files in binary-safe mode to avoid truncation
- Re-save jobs in Spoon after version migrations
When it happens
Trigger: Calling loadXML with a .kjb <entry> node of type SQL that is malformed, missing expected tags, or whose XMLHandler parsing throws KettleXMLException/KettleException (e.g. invalid characters, truncated file).
Common situations: Hand-edited job XML with a broken <sql> entry; file truncated during transfer; XML exported from a newer PDI version with tags the older parser chokes on.
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
- JobEntrySuccess.Meta.UnableToLoadFromXML
- Unable to load job entry of type 'Syslog' from XML node
- ERROR_0001_Cannot_Load_Job_Entry_From_Xml_Node
- JobEntryZipFile.UnableLoadJobEntryXML
- JobMoveFiles.Error.Exception.UnableLoadXML
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/4dc26f168b91b985.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/job/entries/sql/JobEntrySQL.java:138
if ( sSubs != null && sSubs.equalsIgnoreCase( "T" ) ) {
useVariableSubstitution = true;
}
databaseMeta = DatabaseMeta.findDatabase( databases, dbname );
String ssql = XMLHandler.getTagValue( entrynode, SQLFROMFILE_TAG );
if ( ssql != null && ssql.equalsIgnoreCase( "T" ) ) {
sqlFromFile = true;
}
sqlFilename = XMLHandler.getTagValue( entrynode, SQLFILENAME_TAG );
String sOneStatement = XMLHandler.getTagValue( entrynode, SEND_ONE_STATEMENT_TAG );
if ( sOneStatement != null && sOneStatement.equalsIgnoreCase( "T" ) ) {
sendOneStatement = true;
}
} catch ( KettleException e ) {
throw new KettleXMLException( "Unable to load job entry of type 'sql' from XML node", e );
}
}
public void loadRep( Repository rep, IMetaStore metaStore, ObjectId idJobentry, List<DatabaseMeta> databases,
List<SlaveServer> slaveServers ) throws KettleException {
try {
sql = rep.getJobEntryAttributeString( idJobentry, SQL_TAG );
String sSubs = rep.getJobEntryAttributeString( idJobentry, USE_VARIABLE_SUBSTITUTION_TAG );
if ( sSubs != null && sSubs.equalsIgnoreCase( "T" ) ) {
useVariableSubstitution = true;
}
String ssql = rep.getJobEntryAttributeString( idJobentry, SQLFROMFILE_TAG );
if ( ssql != null && ssql.equalsIgnoreCase( "T" ) ) {
sqlFromFile = true;
}
String ssendOneStatement = rep.getJobEntryAttributeString( idJobentry, SEND_ONE_STATEMENT_TAG );View on GitHub (pinned to f3058517a1)