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
- 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
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
- 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
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
- Directory: ${file} is not empty.
- SftpException wrapped (pwd failed while deleting)
- Directory: %s is not empty.
- SftpException wrapped (pwd failed while listing status)
- Path %s is a directory.
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/e1590078158fd8d3.
Report an issue: GitHub.