{"record":{"id":"da75b64e8ce15d04","repo":"pentaho/pentaho-kettle","slug":"unable-to-load-job-entry-of-type-ftp-from-xml-node-da75b6","errorCode":null,"errorMessage":"Unable to load job entry of type 'ftp' from XML node","messagePattern":"Unable to load job entry of type 'ftp' from XML node","errorType":"exception","errorClass":"KettleXMLException","httpStatus":null,"severity":"error","filePath":"plugins/get-file-with-ftp/impl/src/main/java/org/pentaho/di/job/entries/ftp/JobEntryFTP.java","lineNumber":345,"sourceCode":"      SifFileExists = XMLHandler.getTagValue( entrynode, \"ifFileExists\" );\n      if ( Utils.isEmpty( SifFileExists ) ) {\n        ifFileExists = ifFileExistsSkip;\n      } else {\n        if ( SifFileExists.equals( SifFileExistsCreateUniq ) ) {\n          ifFileExists = ifFileExistsCreateUniq;\n        } else if ( SifFileExists.equals( SifFileExistsFail ) ) {\n          ifFileExists = ifFileExistsFail;\n        } else {\n          ifFileExists = ifFileExistsSkip;\n        }\n\n      }\n      nr_limit = XMLHandler.getTagValue( entrynode, \"nr_limit\" );\n      success_condition =\n        Const.NVL( XMLHandler.getTagValue( entrynode, \"success_condition\" ), SUCCESS_IF_NO_ERRORS );\n\n    } catch ( KettleXMLException xe ) {\n      throw new KettleXMLException( \"Unable to load job entry of type 'ftp' from XML node\", xe );\n    }\n  }\n\n  public void loadRep( Repository rep, IMetaStore metaStore, ObjectId id_jobentry, List<DatabaseMeta> databases,\n                       List<SlaveServer> slaveServers ) throws KettleException {\n    try {\n      port = rep.getJobEntryAttributeString( id_jobentry, \"port\" );\n      serverName = rep.getJobEntryAttributeString( id_jobentry, \"servername\" );\n      userName = rep.getJobEntryAttributeString( id_jobentry, \"username\" );\n      password =\n        Encr.decryptPasswordOptionallyEncrypted( rep.getJobEntryAttributeString( id_jobentry, \"password\" ) );\n      ftpDirectory = rep.getJobEntryAttributeString( id_jobentry, \"ftpdirectory\" );\n      targetDirectory = rep.getJobEntryAttributeString( id_jobentry, \"targetdirectory\" );\n      wildcard = rep.getJobEntryAttributeString( id_jobentry, \"wildcard\" );\n      binaryMode = rep.getJobEntryAttributeBoolean( id_jobentry, \"binary\" );\n      timeout = rep.getJobEntryAttributeString( id_jobentry, \"timeout\" );\n      remove = rep.getJobEntryAttributeBoolean( id_jobentry, \"remove\" );\n      onlyGettingNewFiles = rep.getJobEntryAttributeBoolean( id_jobentry, \"only_new\" );","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/get-file-with-ftp/impl/src/main/java/org/pentaho/di/job/entries/ftp/JobEntryFTP.java#L327-L363","documentation":"JobEntryFTP.loadXML() wraps any KettleXMLException raised while deserializing the classic FTP job entry's XML attributes (including nr_limit and success_condition) into a KettleXMLException with the literal message \"Unable to load job entry of type 'ftp' from XML node\". The original exception is chained as cause. It means the <entry type='FTP'> element in the .kjb file is unreadable by XMLHandler or contains values the loader rejects.","triggerScenarios":"Loading job XML where the FTP entry element is malformed, has unexpected tag structure from an older/newer plugin version, or fails inside the try block (getTagValue parsing, NVL handling) — thrown at the catch clause at line 345.","commonSituations":"Hand-edited or script-generated .kjb files; migrating jobs between Kettle/Pentaho versions where the FTP entry XML schema changed; truncated files from bad transfers; copy-paste XML errors.","solutions":["Inspect getCause() to find the failing tag and correct it in the .kjb XML.","Reopen and re-save the FTP job entry in Spoon to regenerate valid XML.","Validate success_condition against allowed constants (e.g., SUCCESS_IF_NO_ERRORS) if that tag is involved.","Ensure the get-file-with-ftp plugin version matches the Pentaho version loading the job."],"exampleFix":"<!-- before: invalid success_condition structure -->\n<success_condition></success_condition>\n<nr_limit />\n<!-- after: valid defaults -->\n<success_condition>success_if_no_errors</success_condition>\n<nr_limit>10</nr_limit>","handlingStrategy":"try-catch","validationCode":"// validate FTP entry tags before loadXML\nString sc = XMLHandler.getTagValue( entrynode, \"success_condition\" );\nif ( sc != null && !sc.equals( \"success_if_no_errors\" ) && !sc.equals( \"success_if_errors_less\" )\n     && !sc.equals( \"success_if_errors_less_than\" ) ) {\n  throw new IllegalArgumentException( \"Invalid success_condition in FTP entry XML: \" + sc );\n}","typeGuard":null,"tryCatchPattern":"try {\n  entry.loadXML( entrynode, databases, metaStore );\n} catch ( KettleXMLException e ) {\n  log.error( \"FTP entry XML load failed: \" + e.getCause() );\n  throw new KettleException( \"Fix the FTP entry XML in the .kjb file and reload\", e );\n}","preventionTips":["Avoid manual XML edits; use the Spoon job entry dialog.","Validate job XML after migrations between Kettle versions.","Keep the FTP plugin version aligned with the server version.","Ensure .kjb files transfer completely (check file size/checksums)."],"tags":["kettle","ftp","xml","deserialization"],"backgroundTag":"xml-unmarshal-failed","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}