{"record":{"id":"e1590078158fd8d3","repo":"apache/seatunnel","slug":"sftpexception-wrapped-ls-failed-while-listing-sta","errorCode":null,"errorMessage":"SftpException wrapped (ls failed while listing status)","messagePattern":"SftpException wrapped \\(ls failed while listing status\\)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-file/connector-file-sftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/sftp/system/SFTPFileSystem.java","lineNumber":420,"sourceCode":"     */\n    @SuppressWarnings(\"unchecked\")\n    private FileStatus[] listStatus(ChannelSftp client, Path file) throws IOException {\n        Path workDir;\n        try {\n            workDir = new Path(client.pwd());\n        } catch (SftpException e) {\n            throw new IOException(e);\n        }\n        Path absolute = makeAbsolute(workDir, file);\n        FileStatus fileStat = getFileStatus(client, absolute);\n        if (!fileStat.isDirectory()) {\n            return new FileStatus[] {fileStat};\n        }\n        Vector<LsEntry> sftpFiles;\n        try {\n            sftpFiles = (Vector<LsEntry>) client.ls(absolute.toUri().getPath());\n        } catch (SftpException e) {\n            throw new IOException(e);\n        }\n        ArrayList<FileStatus> fileStats = new ArrayList<FileStatus>();\n        for (int i = 0; i < sftpFiles.size(); i++) {\n            LsEntry entry = sftpFiles.get(i);\n            String fname = entry.getFilename();\n            // skip current and parent directory, ie. \".\" and \"..\"\n            if (!\".\".equalsIgnoreCase(fname) && !\"..\".equalsIgnoreCase(fname)) {\n                fileStats.add(getFileStatus(client, entry, absolute));\n            }\n        }\n        return fileStats.toArray(new FileStatus[fileStats.size()]);\n    }\n\n    private boolean rename(ChannelSftp channel, Path src, Path dst) throws IOException {\n        Path workDir;\n        try {\n            workDir = new Path(channel.pwd());\n        } catch (SftpException e) {","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-file/connector-file-sftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/sftp/system/SFTPFileSystem.java#L402-L438","documentation":"listStatus() calls client.ls(path) on the resolved absolute path; any SftpException from ls (no such file, permission denied, connection lost) is wrapped into a plain IOException. The wrapper loses the SFTP status code unless you inspect the cause, so 'directory missing' and 'session dead' look identical at first glance.","triggerScenarios":"listStatus(dir) where dir does not exist on the server (ls throws SSH_FX_NO_SUCH_FILE), lacks read permission (SSH_FX_PERMISSION_DENIED), or the channel drops during ls.","commonSituations":"Typo in configured output/input path; path removed by another process mid-job; user account lacks permission on the directory; expired session during a long listing.","solutions":["Verify the path exists on the SFTP server (e.g. check via fs.exists or an sftp client) before listing","Fix permissions so the connecting user can read the directory","Catch IOException, check getCause() instanceof SftpException and its status code to branch on not-found vs permission vs connection","Reconnect and retry when the cause indicates a connection-level failure"],"exampleFix":"// before\nFileStatus[] st = fs.listStatus(new Path(\"/data/in\"));\n// after\nPath in = new Path(\"/data/in\");\nif (fs.exists(in)) {\n    FileStatus[] st = fs.listStatus(in);\n} else {\n    throw new IOException(\"Input dir missing: \" + in);\n}","handlingStrategy":"validation","validationCode":"Path dir = new Path(\"/data/in\");\nif (!fs.exists(dir)) {\n    throw new IOException(\"Directory missing: \" + dir);\n}\nif (!fs.getFileStatus(dir).isDirectory()) {\n    throw new IOException(\"Not a directory: \" + dir);\n}","typeGuard":null,"tryCatchPattern":"try {\n    fs.listStatus(dir);\n} catch (IOException e) {\n    if (e.getCause() instanceof SftpException\n            && ((SftpException) e.getCause()).id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {\n        // handle missing dir explicitly\n    }\n    throw e;\n}","preventionTips":["Verify configured paths exist before the job runs","Grant the SFTP user read permission on target directories","Unwrap SftpException cause to distinguish not-found vs permission vs connection"],"tags":["sftp","io","directory"],"backgroundTag":"file-not-found","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}