{"record":{"id":"eb3e4c7e12c9f893","repo":"pentaho/pentaho-kettle","slug":"interrupted-during-a-retry","errorCode":null,"errorMessage":"Interrupted during a retry ","messagePattern":"Interrupted during a retry ","errorType":"exception","errorClass":"KettleJobException","httpStatus":null,"severity":"warning","filePath":"engine/src/main/java/org/pentaho/di/job/entries/sftp/SFTPClient.java","lineNumber":198,"sourceCode":"    int maxConnectionAttempts = 62;\n    int delayBetweenEachAttempts = 100; // milliseconds\n\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      }","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/job/entries/sftp/SFTPClient.java#L180-L216","documentation":"During login()'s retry loop, the Thread.sleep(delayBetweenEachAttempts) between attempts can throw InterruptedException if the thread is interrupted. The code restores the interrupt flag and rethrows as this KettleJobException so callers know the retry wait was cancelled.","triggerScenarios":"login() sleeping between connection retries when another thread calls interrupt() on the executing job thread (job cancel, shutdown, timeout watchdog).","commonSituations":"User cancels a stalled job in Spoon; job executor times out and interrupts the worker; application shutdown interrupting background retry loops.","solutions":["Treat this as an intentional cancellation: stop the SFTP operation rather than retrying.","Identify what interrupted the thread (job cancel/timeout) and adjust those settings if the interruption is unwanted.","Avoid long delays between attempts so sleeps are short and cancellation windows small.","Preserve the interrupt status in any wrapping code (the library already calls Thread.currentThread().interrupt())."],"exampleFix":"// before\ncatch (KettleJobException e) { /* ignore and continue */ }\n// after\ncatch (KettleJobException e) {\n  if (Thread.currentThread().isInterrupted()) { log.info(\"cancelled\"); return; }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  client.login();\n} catch (KettleJobException e) {\n  if (Thread.currentThread().isInterrupted()) {\n    log.info(\"Login retries cancelled by interrupt\");\n    return; // graceful cancellation\n  }\n  throw e;\n}","preventionTips":["Design job cancellation paths to expect and honor this error.","Keep retry delays short to reduce interruption windows.","Never swallow InterruptedException without restoring the interrupt flag."],"tags":["sftp","retry","thread","interruption"],"backgroundTag":"thread-interrupted","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"}