pentaho/pentaho-kettle · error · KettleXMLException
JobCopyFiles.Error.Exception.UnableLoadXML
Error message
JobCopyFiles.Error.Exception.UnableLoadXML
What it means
JobEntryCopyFiles.loadXML throws this KettleXMLException when parsing the job entry's XML definition fails. It wraps the original KettleXMLException so the caller knows the 'copy files' job entry could not be deserialized from a .kjb file. The message is localized via BaseMessages from the messages package.
Solutions
- Validate the .kjb XML: ensure the COPY_FILES entry node has well-formed <fields> with <source_filefolder>, <destination_filefolder> and <wildcard> children and a matching field count.
- Open the job in Spoon to let the designer repair the entry, then re-save.
- Check version compatibility of the job file with your Pentaho DI version.
- Inspect the chained KettleXMLException (getCause()) for the exact parse error location.
Example fix
// before (hand-edited XML) <fields><source_filefolder>/tmp/a</source_filefolder></fields> // after <fields><field><source_filefolder>/tmp/a</source_filefolder><destination_filefolder>/tmp/b</destination_filefolder><wildcard>.*\.txt</wildcard></field></fields>
Defensive patterns
Strategy: try-catch
Validate before calling
// before loading from XML
Document doc = XMLHandler.loadXMLFile(jobFile);
Node entry = XMLHandler.getSubNode(doc, "entry");
if (entry == null || !"COPY_FILES".equals(XMLHandler.getTagAttribute(entry, "type"))) {
throw new IllegalArgumentException("Not a valid COPY_FILES entry node");
}
if (XMLHandler.getSubNode(entry, "fields") == null) {
throw new IllegalArgumentException("COPY_FILES entry is missing <fields> block");
} Try / catch
try {
jobEntry.loadXML(entrynode, databases, slaveServers, rep, metaStore);
} catch (KettleXMLException e) {
logError("Failed to parse COPY_FILES entry: " + e.getCause(), e);
// fall back to rebuilding the entry or aborting job load
} Prevention
- Never hand-edit .kjb files; edit via Spoon
- Keep job files in version control to restore known-good versions
- Match Pentaho DI versions when moving job files between environments
- Validate XML well-formedness with an XML parser before loading
When it happens
Trigger: Calling loadXML (via JobMeta loading from XML, e.g. JobMeta(fileName) or saveLoad paths) on a <entry type='COPY_FILES'> node whose structure is malformed: missing/corrupt <source_filefolder>, <destination_filefolder> or <wildcard> tags, a non-numeric or missing nr-fields/argument count attribute, or non-XML content passed as the entry node.
Common situations: Hand-edited or truncated .kjb job files; jobs exported from newer Pentaho versions then opened in older ones; copying job XML between repositories or generating XML programmatically with wrong tag names.
Related errors
- JobEntryCopyMoveResultFilenames.CanNotLoadFromXML
- JobEntryMSAccessBulkLoad.Meta.UnableLoadXML
- Unable to load job entry of type 'create file' from XML node
- Unable to load job entry of type 'create folder' from XML…
- CubeInputMeta.Exception.UnableToLoadStepInfo
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/9c6fb7180bb52a86.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/job/entries/copyfiles/JobEntryCopyFiles.java:211
create_destination_folder =
"Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "create_destination_folder" ) );
Node fields = XMLHandler.getSubNode( entrynode, "fields" );
// How many field arguments?
int nrFields = XMLHandler.countNodes( fields, "field" );
allocate( nrFields );
// Read them all...
for ( int i = 0; i < nrFields; i++ ) {
Node fnode = XMLHandler.getSubNodeByNr( fields, "field", i );
source_filefolder[i] = loadSource( fnode );
destination_filefolder[i] = loadDestination( fnode );
wildcard[i] = XMLHandler.getTagValue( fnode, "wildcard" );
}
} catch ( KettleXMLException xe ) {
throw new KettleXMLException(
BaseMessages.getString( PKG, "JobCopyFiles.Error.Exception.UnableLoadXML" ), xe );
}
}
protected String loadSource( Node fnode ) {
String source_filefolder = XMLHandler.getTagValue( fnode, SOURCE_FILE_FOLDER );
String ncName = XMLHandler.getTagValue( fnode, SOURCE_CONFIGURATION_NAME );
return loadURL( source_filefolder, ncName, getMetaStore(), configurationMappings );
}
protected String loadDestination( Node fnode ) {
String destination_filefolder = XMLHandler.getTagValue( fnode, DESTINATION_FILE_FOLDER );
String ncName = XMLHandler.getTagValue( fnode, DESTINATION_CONFIGURATION_NAME );
return loadURL( destination_filefolder, ncName, getMetaStore(), configurationMappings );
}
protected void saveSource( StringBuilder retval, String source ) {
String namedCluster = configurationMappings.get( source );View on GitHub (pinned to f3058517a1)