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 else

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Check fs.getFileStatus(path).isDirectory() before opening and iterate directory entries instead
  2. Correct the configured path to point at the actual file
  3. If the intent is to read all files under a directory, list the directory and open each child file
  4. 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

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


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