apache/seatunnel · error · IOException
Path %s is a directory.
Error message
Path %s is a directory.
What it means
open() resolves the file status and throws IOException(E_PATH_DIR) if the target path is a directory — you can only open regular files for reading. Symbolic links are subsequently resolved via channel.realpath, but an actual directory cannot be opened as a stream.
Source
Thrown at seatunnel-connectors-v2/connector-file/connector-file-sftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/sftp/system/SFTPFileSystem.java:489
@Override
public String getScheme() {
return "sftp";
}
@Override
public URI getUri() {
return uri;
}
@Override
public FSDataInputStream open(Path f, int bufferSize) throws IOException {
ChannelSftp channel = connect();
try {
Path workDir = new Path(channel.pwd());
Path absolute = makeAbsolute(workDir, f);
FileStatus fileStat = getFileStatus(channel, absolute);
if (fileStat.isDirectory()) {
throw new IOException(String.format(E_PATH_DIR, f));
}
// the path could be a symbolic link, so get the real path
absolute = new Path("/", channel.realpath(absolute.toUri().getPath()));
InputStream is = channel.get(quote(absolute.toUri().getPath()));
return new FSDataInputStream(
new SFTPInputStream(is, channel, connectionPool, statistics));
} catch (Exception e) {
disconnectAfterFailure(channel, e);
if (e instanceof IOException) {
throw (IOException) e;
}
throw new IOException(e);
}
}
/**
* A stream obtained via this call must be closed before using other APIs of this class or elseView on GitHub (pinned to cf67b549a7)
Solutions
- Check fs.getFileStatus(path).isDirectory() before opening and iterate directory entries instead
- Correct the configured path to point at the actual file
- If the intent is to read all files under a directory, list the directory and open each child file
- Verify on the server (sftp ls -l) what the path actually is
Example fix
// before
FSDataInputStream in = fs.open(new Path("/data/in"));
// after
Path p = new Path("/data/in");
if (fs.getFileStatus(p).isDirectory()) {
throw new IllegalArgumentException("Expected a file: " + p);
}
FSDataInputStream in = fs.open(p); Defensive patterns
Strategy: validation
Validate before calling
Path p = new Path("/data/in/file.txt");
FileStatus st = fs.getFileStatus(p);
if (st.isDirectory()) {
throw new IllegalArgumentException("Expected a file, got directory: " + p);
} Try / catch
try {
fs.open(p);
} catch (IOException e) {
if (String.valueOf(e.getMessage()).contains("is a directory")) {
// list dir and open children instead
} else { throw e; }
} Prevention
- Always validate isDirectory() before open
- Build paths carefully when concatenating (don't drop the filename)
- Inspect server with ls -l when path types are uncertain
When it happens
Trigger: fs.open(path) where path points to a directory on the SFTP server (e.g. a directory was configured as an input file, or the path glob resolved to a directory).
Common situations: Configuring a directory instead of a file as input; a job expects a file but a same-named directory exists on the server; path built by string concatenation lost the filename portion.
Related errors
- SftpException wrapped (pwd failed while deleting)
- SftpException wrapped (pwd failed while listing status)
- SftpException wrapped (ls failed while listing status)
- Source path %s does not exist
- Generic exception wrapped (open failed)
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/cb83c6d7cbbbe832.
Report an issue: GitHub.