pentaho/pentaho-kettle · error · KettleXMLException

JobFoldersCompare.Meta.UnableLoadXML

Error message

JobFoldersCompare.Meta.UnableLoadXML

What it means

Thrown by JobEntryFoldersCompare.loadXML when parsing the job entry's XML node fails with a KettleXMLException. The message is a localized bundle key (JobFoldersCompare.Meta.UnableLoadXML) with the original message substituted. It means the 'Compare Folders' entry could not be read from a .kjb XML document.

Solutions

  1. Open the .kjb file in an XML validator/editor and fix the malformed entry node (compareonly, wildcard, filename1, filename2 tags).
  2. Check xe.getMessage() in the wrapped exception for the exact XML parse error and line.
  3. Re-export the job from Spoon to regenerate valid XML.
  4. Ensure the file encoding matches the declared encoding (UTF-8) and the file is not truncated.

Example fix

// before: hand-edited node missing closing tag
<folders_compare><filename1>/a</filename1>
// after: valid complete node
<folders_compare>
  <compareonly>N</compareonly>
  <filename1>/data/a</filename1>
  <filename2>/data/b</filename2>
</folders_compare>
Defensive patterns

Strategy: validation

Validate before calling

// validate XML before loading
Document doc = XMLHandler.loadXMLFile(kjbInputStream);
if (doc == null) throw new KettleException("Invalid or empty .kjb XML");
Node entryNode = XMLHandler.getSubNode(doc, "entry");
if (entryNode == null) throw new KettleException("Missing <entry> node");

Try / catch

try {
  entry.loadXML(entryNode, databases, slaveServers, rep, metaStore);
} catch (KettleXMLException e) {
  logError("FoldersCompare XML load failed: " + e.getMessage());
  // fix or re-export the .kjb file
}

Prevention

When it happens

Trigger: Calling loadXML on JobEntryFoldersCompare when XMLHandler.getTagValue/getSubNode throws KettleXMLException — malformed XML, wrong node structure, or an XML parsing error inside the entry's <entry> block.

Common situations: Hand-edited .kjb files with invalid XML; job files truncated by a failed transfer; version drift where the XML schema changed; copy-pasting an entry node from another job with mismatched tags.

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


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/a99110d5e6d7f77e. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/job/entries/folderscompare/JobEntryFoldersCompare.java:138

      parentJobMeta.getNamedClusterEmbedManager().registerUrl( filename2 );
    }
    return retval.toString();
  }

  public void loadXML( Node entrynode, List<DatabaseMeta> databases, List<SlaveServer> slaveServers,
    Repository rep, IMetaStore metaStore ) throws KettleXMLException {
    try {
      super.loadXML( entrynode, databases, slaveServers );
      includesubfolders = "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "include_subfolders" ) );
      comparefilecontent = "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "compare_filecontent" ) );
      comparefilesize = "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "compare_filesize" ) );

      compareonly = XMLHandler.getTagValue( entrynode, "compareonly" );
      wildcard = XMLHandler.getTagValue( entrynode, "wildcard" );
      filename1 = XMLHandler.getTagValue( entrynode, "filename1" );
      filename2 = XMLHandler.getTagValue( entrynode, "filename2" );
    } catch ( KettleXMLException xe ) {
      throw new KettleXMLException( BaseMessages.getString( PKG, "JobFoldersCompare.Meta.UnableLoadXML", xe
        .getMessage() ) );
    }
  }

  public void loadRep( Repository rep, IMetaStore metaStore, ObjectId id_jobentry, List<DatabaseMeta> databases,
    List<SlaveServer> slaveServers ) throws KettleException {
    try {
      includesubfolders = rep.getJobEntryAttributeBoolean( id_jobentry, "include_subfolders" );
      comparefilecontent = rep.getJobEntryAttributeBoolean( id_jobentry, "compare_filecontent" );
      comparefilesize = rep.getJobEntryAttributeBoolean( id_jobentry, "compare_filesize" );

      compareonly = rep.getJobEntryAttributeString( id_jobentry, "compareonly" );
      wildcard = rep.getJobEntryAttributeString( id_jobentry, "wildcard" );
      filename1 = rep.getJobEntryAttributeString( id_jobentry, "filename1" );
      filename2 = rep.getJobEntryAttributeString( id_jobentry, "filename2" );
    } catch ( KettleException dbe ) {
      throw new KettleException( BaseMessages.getString( PKG, "JobFoldersCompare.Meta.UnableLoadRep", ""
        + id_jobentry, dbe.getMessage() ) );

View on GitHub (pinned to f3058517a1)