apache/seatunnel · error · IOException

SftpException wrapped (ls failed while listing status)

Error message

SftpException wrapped (ls failed while listing status)

What it means

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.

Source

Thrown at seatunnel-connectors-v2/connector-file/connector-file-sftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/sftp/system/SFTPFileSystem.java:420

     */
    @SuppressWarnings("unchecked")
    private FileStatus[] listStatus(ChannelSftp client, Path file) throws IOException {
        Path workDir;
        try {
            workDir = new Path(client.pwd());
        } catch (SftpException e) {
            throw new IOException(e);
        }
        Path absolute = makeAbsolute(workDir, file);
        FileStatus fileStat = getFileStatus(client, absolute);
        if (!fileStat.isDirectory()) {
            return new FileStatus[] {fileStat};
        }
        Vector<LsEntry> sftpFiles;
        try {
            sftpFiles = (Vector<LsEntry>) client.ls(absolute.toUri().getPath());
        } catch (SftpException e) {
            throw new IOException(e);
        }
        ArrayList<FileStatus> fileStats = new ArrayList<FileStatus>();
        for (int i = 0; i < sftpFiles.size(); i++) {
            LsEntry entry = sftpFiles.get(i);
            String fname = entry.getFilename();
            // skip current and parent directory, ie. "." and ".."
            if (!".".equalsIgnoreCase(fname) && !"..".equalsIgnoreCase(fname)) {
                fileStats.add(getFileStatus(client, entry, absolute));
            }
        }
        return fileStats.toArray(new FileStatus[fileStats.size()]);
    }

    private boolean rename(ChannelSftp channel, Path src, Path dst) throws IOException {
        Path workDir;
        try {
            workDir = new Path(channel.pwd());
        } catch (SftpException e) {

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Verify the path exists on the SFTP server (e.g. check via fs.exists or an sftp client) before listing
  2. Fix permissions so the connecting user can read the directory
  3. Catch IOException, check getCause() instanceof SftpException and its status code to branch on not-found vs permission vs connection
  4. Reconnect and retry when the cause indicates a connection-level failure

Example fix

// before
FileStatus[] st = fs.listStatus(new Path("/data/in"));
// after
Path in = new Path("/data/in");
if (fs.exists(in)) {
    FileStatus[] st = fs.listStatus(in);
} else {
    throw new IOException("Input dir missing: " + in);
}
Defensive patterns

Strategy: validation

Validate before calling

Path dir = new Path("/data/in");
if (!fs.exists(dir)) {
    throw new IOException("Directory missing: " + dir);
}
if (!fs.getFileStatus(dir).isDirectory()) {
    throw new IOException("Not a directory: " + dir);
}

Try / catch

try {
    fs.listStatus(dir);
} catch (IOException e) {
    if (e.getCause() instanceof SftpException
            && ((SftpException) e.getCause()).id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
        // handle missing dir explicitly
    }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/e1590078158fd8d3. Report an issue: GitHub.