pentaho/pentaho-kettle · error · KettleXMLException

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

Error message

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

What it means

KettleXMLException thrown by JobEntryFTPSGet.loadXML when any step of reading the job entry's attributes from its XML node throws — e.g. malformed XML, missing tags, or a bad connection_type code passed to FTPSConnection.getConnectionTypeByCode.

Solutions

  1. Open the .kjb file in an XML editor and validate well-formedness of the FTPSGet entry node
  2. Check the connection_type value in the XML matches a known FTPSConnection code
  3. Regenerate or re-save the job entry in Spoon with the same plugin version
  4. Compare with a working job file to find the missing/corrupt tag

Example fix

<!-- before -->
<connection_type>UNKNOWN_TYPE</connection_type>
<!-- after -->
<connection_type>FTPES</connection_type>
Defensive patterns

Strategy: validation

Validate before calling

// validate the XML node before load
String type = XMLHandler.getTagValue(entrynode, "connection_type");
if (type != null && !knownConnectionTypes.contains(type))
  throw new KettleXMLException("Unknown connection_type: " + type);

Try / catch

try {
  jobEntry.loadXML(entrynode, databases, metaStore);
} catch (KettleXMLException xe) {
  logError("Corrupt FTPS job entry XML: " + xe.getMessage(), xe);
  throw xe;
}

Prevention

When it happens

Trigger: loading a .kjb job file whose FTPSGet entry node has malformed/unexpected XML, or an unrecognized connection_type value that getConnectionTypeByCode cannot map

Common situations: job file edited by hand or produced by a different PDI version; XML escaping broken; connection_type attribute changed/renamed between plugin versions

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at plugins/ftps/impl/src/main/java/org/pentaho/di/job/entries/ftpsget/JobEntryFTPSGet.java:256

      }

      createmovefolder = "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "createmovefolder" ) );

      proxyHost = XMLHandler.getTagValue( entrynode, "proxy_host" );
      proxyPort = XMLHandler.getTagValue( entrynode, "proxy_port" );
      proxyUsername = XMLHandler.getTagValue( entrynode, "proxy_username" );
      proxyPassword =
        Encr.decryptPasswordOptionallyEncrypted( XMLHandler.getTagValue( entrynode, "proxy_password" ) );

      ifFileExists = getFileExistsIndex( XMLHandler.getTagValue( entrynode, "ifFileExists" ) );
      nr_limit = XMLHandler.getTagValue( entrynode, "nr_limit" );
      success_condition =
        Const.NVL( XMLHandler.getTagValue( entrynode, "success_condition" ), SUCCESS_IF_NO_ERRORS );
      connectionType =
        FTPSConnection.getConnectionTypeByCode( Const.NVL(
          XMLHandler.getTagValue( entrynode, "connection_type" ), "" ) );
    } catch ( Exception xe ) {
      throw new KettleXMLException( "Unable to load job entry of type 'FTPS' from XML node", xe );
    }
  }

  public void loadRep( Repository rep, IMetaStore metaStore, ObjectId id_jobentry, List<DatabaseMeta> databases,
                       List<SlaveServer> slaveServers ) throws KettleException {
    try {
      port = rep.getJobEntryAttributeString( id_jobentry, "port" );
      serverName = rep.getJobEntryAttributeString( id_jobentry, "servername" );
      userName = rep.getJobEntryAttributeString( id_jobentry, "username" );
      password =
        Encr.decryptPasswordOptionallyEncrypted( rep.getJobEntryAttributeString( id_jobentry, "password" ) );
      FTPSDirectory = rep.getJobEntryAttributeString( id_jobentry, "FTPSdirectory" );
      targetDirectory = rep.getJobEntryAttributeString( id_jobentry, "targetdirectory" );
      wildcard = rep.getJobEntryAttributeString( id_jobentry, "wildcard" );
      binaryMode = rep.getJobEntryAttributeBoolean( id_jobentry, "binary" );
      timeout = rep.getJobEntryAttributeString( id_jobentry, "timeout" );
      remove = rep.getJobEntryAttributeBoolean( id_jobentry, "remove" );
      onlyGettingNewFiles = rep.getJobEntryAttributeBoolean( id_jobentry, "only_new" );

View on GitHub (pinned to f3058517a1)