{"record":{"id":"f0c88c4efe4c5667","repo":"pentaho/pentaho-kettle","slug":"failed-to-download-file","errorCode":null,"errorMessage":"Failed to download file: ","messagePattern":"Failed to download file: ","errorType":"exception","errorClass":"SftpException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/core/ssh/mina/MinaSftpSession.java","lineNumber":90,"sourceCode":"  }\n\n  @Override\n  public long size( String path ) throws SftpException {\n    try {\n      return client.stat( path ).getSize();\n    } catch ( IOException e ) {\n      throw new SftpException( \"Failed to get file size: \" + path, e );\n    }\n  }\n\n  @Override\n  public void download( String remote, OutputStream target ) throws SftpException {\n    try {\n      try ( InputStream in = client.read( remote ) ) {\n        in.transferTo( target );\n      }\n    } catch ( IOException e ) {\n      throw new SftpException( \"Failed to download file: \" + remote, e );\n    }\n  }\n\n  @Override\n  public void upload( InputStream source, String remote, boolean overwrite ) throws SftpException {\n    try {\n      try ( SftpClient.CloseableHandle h = client.open( remote, SftpClient.OpenMode.Write, SftpClient.OpenMode.Create,\n        SftpClient.OpenMode.Truncate ) ) {\n        byte[] buf = new byte[ 8192 ];\n        int r;\n        long off = 0;\n        while ( ( r = source.read( buf ) ) >= 0 ) {\n          if ( r == 0 ) {\n            continue;\n          }\n          client.write( h, off, buf, 0, r );\n          off += r;\n        }","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/core/ssh/mina/MinaSftpSession.java#L72-L108","documentation":"MinaSftpSession.download() wraps IOException from client.read(remote) and stream transfer into an SftpException. The remote file could not be opened/read or the local output stream failed mid-transfer. Any interruption of the data channel aborts the download with this message.","triggerScenarios":"Calling download(remote, target) when the remote file is missing/unreadable, the network drops mid-transfer, the SFTP session times out, or the local OutputStream (e.g. FileOutputStream) throws while writing.","commonSituations":"Large-file downloads interrupted by NAT/firewall idle timeouts, disk-full or permission errors on the local output file, remote file deleted between listing and download, or concurrent modification of the remote file.","solutions":["Retry the download with backoff; SFTP transfers are safe to retry into a fresh stream","Verify the local OutputStream target is writable and has enough disk space","Check the remote file exists and is readable before downloading","For large transfers, keep-alive or increase SSH session timeouts to survive long reads"],"exampleFix":"// before\nsession.download(remote, new FileOutputStream(localFile));\n// after\nFile outFile = new File(localFile);\ntry (OutputStream out = new FileOutputStream(outFile)) {\n  session.download(remote, out);\n} catch (IOException io) {\n  throw new IOException(\"Local write failed for \" + localFile, io);\n}","handlingStrategy":"retry","validationCode":"try { long expected = session.size(remote); if (expected <= 0) throw new IllegalStateException(\"empty/missing remote file\"); }\ncatch (SftpException e) { throw new IllegalStateException(\"remote not downloadable: \" + remote, e); }\n// ensure local target writable\nif (!localFile.getParentFile().canWrite()) throw new IllegalStateException(\"local dir not writable\");","typeGuard":"boolean downloadable(MinaSftpSession s, String r) {\n  try { return s.size(r) >= 0; } catch (SftpException e) { return false; }\n}","tryCatchPattern":"for (int i = 0; i < 3; i++) {\n  try (OutputStream out = new FileOutputStream(tmpFile)) {\n    session.download(remote, out);\n    Files.move(tmpFile.toPath(), localPath, StandardCopyOption.REPLACE_EXISTING);\n    break;\n  } catch (SftpException | IOException e) {\n    if (i == 2) throw new IOException(\"download failed after retries\", e);\n    sleep(backoff(i));\n  }\n}","preventionTips":["Download to a temp file and rename atomically so retries never leave corrupt partials","Increase session/server timeouts and enable keep-alive for large files","Verify disk space and write permission on the local target before starting","Retry transient IO failures with backoff; check e.getCause() to classify permanent vs transient"],"tags":["sftp","ssh","download","network","io"],"backgroundTag":"file-read-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"}