{"record":{"id":"a19ba62694d82db9","repo":"pentaho/pentaho-kettle","slug":"an-unexpected-error-has-occurred","errorCode":null,"errorMessage":"An unexpected error has occurred ","messagePattern":"An unexpected error has occurred ","errorType":"exception","errorClass":"KettleJobException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/job/entries/sftp/SFTPClient.java","lineNumber":200,"sourceCode":"\n    while ( true ) {\n      try {\n        if ( tryCreateNewConnection( ) ) {\n          break;\n        }\n\n        if ( --maxConnectionAttempts <= 0 ) {\n          throw new KettleJobException( \"Max connection attempts reached\" );\n        }\n        Thread.sleep( delayBetweenEachAttempts );\n        // incrementing delay by 100 milliseconds\n        delayBetweenEachAttempts += 100;\n\n      } catch ( InterruptedException ex ) {\n        Thread.currentThread().interrupt();\n        throw new KettleJobException( \"Interrupted during a retry \", ex );\n      } catch ( Exception e ) {\n        throw new KettleJobException( \"An unexpected error has occurred \", e );\n      }\n    }\n  }\n\n  private boolean tryCreateNewConnection(  ) {\n    try {\n      session.setPassword( this.getPassword() );\n      java.util.Properties config = new java.util.Properties();\n      config.put( \"StrictHostKeyChecking\", \"no\" );\n      // set compression property\n      // zlib, none\n      String compress = getCompression();\n      if ( compress != null ) {\n        config.put( COMPRESSION_S2C, compress );\n        config.put( COMPRESSION_C2S, compress );\n      }\n      config.put( \"ConnectTimeout\", \"30000\" );\n      config.put( \"SocketTimeout\", \"30000\" );","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/job/entries/sftp/SFTPClient.java#L182-L218","documentation":"Catch-all in login()'s retry loop: any unexpected exception from tryCreateNewConnection() or surrounding code (other than InterruptedException) is rethrown as this KettleJobException with the original as cause. It signals an unforeseen failure during the connection attempt.","triggerScenarios":"login() where tryCreateNewConnection() throws any non-interrupt Exception - e.g. JSch session/auth errors surfaced as runtime exceptions, NPEs from null configuration, or unexpected state.","commonSituations":"Null fields in SFTP entry config causing NPEs; JSch version incompatibilities; unexpected server responses during handshake; bugs in connection setup.","solutions":["Inspect the wrapped cause (e.getCause()) to identify the true failure.","Validate all SFTP entry fields (host, port, user, password/key) are non-null before login.","Check the JSch dependency version matches what this Pentaho version expects.","Reproduce with JSch logging enabled to capture the handshake failure detail."],"exampleFix":"// before\nclient.login(); // NPE when password field null\n// after\nObjects.requireNonNull(password, \"password required\");\nclient.login();","handlingStrategy":"try-catch","validationCode":"Objects.requireNonNull(host, \"host\");\nObjects.requireNonNull(user, \"user\");\nassert port > 0 : \"port must be positive\";","typeGuard":null,"tryCatchPattern":"try {\n  client.login();\n} catch (KettleJobException e) {\n  Throwable root = e;\n  while (root.getCause() != null) root = root.getCause();\n  logError(\"Unexpected login failure, root cause: \" + root);\n}","preventionTips":["Unwrap and log the root cause of every login failure.","Null-check all config fields before login.","Enable JSch debug logging in staging to catch handshake anomalies."],"tags":["sftp","retry","unexpected-exception","connection"],"backgroundTag":"network-request-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"}