pentaho/pentaho-kettle · error · KettleXMLException

Unable to load job entry of type 'unzip' from XML node

Error message

Unable to load job entry of type 'unzip' from XML node

What it means

JobEntryUnZip.loadXML() wraps a KettleXMLException raised while reading the 'unzip' job entry's XML attributes into a new KettleXMLException with message "Unable to load job entry of type 'unzip' from XML node". It indicates the XML node for the unzip entry is malformed or contains values that cannot be parsed (e.g. the 'iffileexists' enum).

Solutions

  1. Open the .kjb and inspect the <entry type='UNZIP'> node; correct or remove invalid attribute values.
  2. Ensure 'iffileexists' contains a recognized code (e.g. 'rename', 'overwrite', 'fail', 'skip').
  3. Recreate the UnZip job entry in Spoon to regenerate valid XML.
  4. Diff the XML against a working job from the same Kettle version.

Example fix

// before: invalid iffileexists value in .kjb
<iffileexists>replace</iffileexists>
// after
<iffileexists>overwrite</iffileexists>
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate unzip entry XML attributes before loadXML
String iffe = XMLHandler.getTagValue(entrynode, "iffileexists");
if ( iffe != null && !(iffe.equals("rename")||iffe.equals("overwrite")||iffe.equals("fail")||iffe.equals("skip")) )
  throw new KettleXMLException("Unknown iffileexists code: " + iffe);

Type guard

boolean isValidUnzipNode(Node entrynode) {
  return entrynode != null
    && XMLHandler.getTagValue(entrynode, "zipfilename") != null;
}

Try / catch

try {
  jobEntry.loadXML(entrynode, databases, slaveServers, rep, metaStore);
} catch ( KettleXMLException e ) {
  logError("Cannot parse unzip entry XML: " + e.getCause().getMessage(), e);
  // reject the job file or substitute defaults
}

Prevention

When it happens

Trigger: Calling loadXML(...) with an entrynode whose attributes like 'iffileexists' or 'create_move_to_directory' are missing/unparseable, so getIfFileExistsInt or XMLHandler throws KettleXMLException.

Common situations: .kjb files edited by hand or by third-party tools; unknown 'iffileexists' code from a newer/older Kettle version; truncated XML export.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/job/entries/unzip/JobEntryUnZip.java:237

      addtime = "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "addtime" ) );
      addOriginalTimestamp = "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "addOriginalTimestamp" ) );
      SpecifyFormat = "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "SpecifyFormat" ) );
      date_time_format = XMLHandler.getTagValue( entrynode, "date_time_format" );
      rootzip = "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "rootzip" ) );
      createfolder = "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "createfolder" ) );
      nr_limit = XMLHandler.getTagValue( entrynode, "nr_limit" );
      wildcardSource = XMLHandler.getTagValue( entrynode, "wildcardSource" );
      success_condition = XMLHandler.getTagValue( entrynode, "success_condition" );
      if ( Utils.isEmpty( success_condition ) ) {
        success_condition = SUCCESS_IF_NO_ERRORS;
      }
      iffileexist = getIfFileExistsInt( XMLHandler.getTagValue( entrynode, "iffileexists" ) );
      createMoveToDirectory =
        "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "create_move_to_directory" ) );
      setOriginalModificationDate =
        "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "setOriginalModificationDate" ) );
    } catch ( KettleXMLException xe ) {
      throw new KettleXMLException( "Unable to load job entry of type 'unzip' from XML node", xe );
    }
  }

  public void loadRep( Repository rep, IMetaStore metaStore, ObjectId id_jobentry, List<DatabaseMeta> databases,
    List<SlaveServer> slaveServers ) throws KettleException {
    try {
      zipFilename = rep.getJobEntryAttributeString( id_jobentry, "zipfilename" );
      afterunzip = (int) rep.getJobEntryAttributeInteger( id_jobentry, "afterunzip" );
      wildcard = rep.getJobEntryAttributeString( id_jobentry, "wildcard" );
      wildcardexclude = rep.getJobEntryAttributeString( id_jobentry, "wildcardexclude" );
      sourcedirectory = rep.getJobEntryAttributeString( id_jobentry, "targetdirectory" );
      movetodirectory = rep.getJobEntryAttributeString( id_jobentry, "movetodirectory" );
      addfiletoresult = rep.getJobEntryAttributeBoolean( id_jobentry, "addfiletoresult" );
      isfromprevious = rep.getJobEntryAttributeBoolean( id_jobentry, "isfromprevious" );
      adddate = rep.getJobEntryAttributeBoolean( id_jobentry, "adddate" );
      addtime = rep.getJobEntryAttributeBoolean( id_jobentry, "addtime" );
      addOriginalTimestamp = rep.getJobEntryAttributeBoolean( id_jobentry, "addOriginalTimestamp" );
      SpecifyFormat = rep.getJobEntryAttributeBoolean( id_jobentry, "SpecifyFormat" );

View on GitHub (pinned to f3058517a1)