pentaho/pentaho-kettle · error · KettleXMLException
Unable to load job entry of type 'mail' from XML node
Error message
Unable to load job entry of type 'mail' from XML node
What it means
Outer catch-all while loading the 'mail' job entry from its XML node: an exception occurred parsing the entry's settings (zip options, reply-to, embedded images). The message identifies the entry type; the underlying exception is chained.
Solutions
- Inspect the chained KettleException cause to find the exact XML node/tag that failed to parse.
- Open the .kjb in Spoon and re-save the Mail job entry to regenerate well-formed XML.
- Restore the job file from version control if it was hand-edited or truncated.
- Match Pentaho/PDI versions if the job came from a different release.
Defensive patterns
Strategy: validation
Validate before calling
// Validate the job XML before loading
Document doc = XMLHandler.loadXMLFile(new File(jobFile));
if (doc == null || XMLHandler.getSubNode(doc, "job") == null) {
throw new KettleException(jobFile + " is not a valid job XML file.");
} Try / catch
try { loadJob(xmlNode); } catch (KettleXMLException e) {
logError("Mail job entry XML is malformed; re-save the .kjb in Spoon: " + e.getMessage(), e);
} Prevention
- Do not hand-edit .kjb files; edit via Spoon.
- Resolve VCS merges of job XML by re-saving from Spoon, not by hand.
- Keep job producers and consumers on compatible PDI versions.
When it happens
Trigger: loadXML reads embedded image nodes and tags from the entrynode and any malformed/missing node or unexpected structure raises KettleException, e.g. a hand-edited .kjb or a file written by an incompatible Pentaho version.
Common situations: Hand-edited job XML with broken <embedded_image> nodes; jobs from newer/older Pentaho versions with changed XML schema; truncated file from a failed VCS merge.
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
- JobEntryMailValidator.Meta.UnableToLoadFromXML
- ERROR_0001_Cannot_Load_Job_Entry_From_Xml_Node
- ERROR_0001_Cannot_Load_Job_Entry_From_Xml_Node
- ERROR_0001_Cannot_Load_Job_Entry_From_Xml_Node
- ERROR_0001_Unable_To_Load_From_Xml_Node
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/e7bf27e409791e47.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/mail-job/impl/src/main/java/org/pentaho/di/job/entries/mail/JobEntryMail.java:419
setZipFiles( "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, TAG_ZIP_FILES ) ) );
setZipFilename( XMLHandler.getTagValue( entrynode, TAG_ZIP_NAME ) );
setReplyToAddresses( XMLHandler.getTagValue( entrynode, TAG_REPLY_TO_ADDRESSES ) );
Node images = XMLHandler.getSubNode( entrynode, TAG_EMBEDDED_IMAGES );
// How many field embedded images ?
int nrImages = XMLHandler.countNodes( images, TAG_EMBEDDED_IMAGE );
allocateImages( nrImages );
// Read them all...
for ( int i = 0; i < nrImages; i++ ) {
Node fnode = XMLHandler.getSubNodeByNr( images, TAG_EMBEDDED_IMAGE, i );
embeddedimages[i] = XMLHandler.getTagValue( fnode, TAG_IMAGE_NAME );
contentids[i] = XMLHandler.getTagValue( fnode, TAG_CONTENT_ID );
}
} catch ( KettleException xe ) {
throw new KettleXMLException( "Unable to load job entry of type 'mail' from XML node", xe );
}
}
@Override
public void loadRep( Repository rep, IMetaStore metaStore, ObjectId idJobEntry, List<DatabaseMeta> databases,
List<SlaveServer> slaveServers ) throws KettleException {
try {
// First load the common parts like name & description, then the attributes...
//
server = rep.getJobEntryAttributeString( idJobEntry, TAG_SERVER );
port = rep.getJobEntryAttributeString( idJobEntry, TAG_PORT );
destination = rep.getJobEntryAttributeString( idJobEntry, TAG_DESTINATION );
destinationCc = rep.getJobEntryAttributeString( idJobEntry, TAG_DESTINATION_CC );
destinationBCc = rep.getJobEntryAttributeString( idJobEntry, TAG_DESTINATION_BCC );
replyAddress = rep.getJobEntryAttributeString( idJobEntry, TAG_REPLYTO );
replyName = rep.getJobEntryAttributeString( idJobEntry, TAG_REPLYTONAME );
subject = rep.getJobEntryAttributeString( idJobEntry, TAG_SUBJECT );
includeDate = rep.getJobEntryAttributeBoolean( idJobEntry, TAG_INCLUDE_DATE );View on GitHub (pinned to f3058517a1)