{"record":{"id":"cb83c6d7cbbbe832","repo":"apache/seatunnel","slug":"path-s-is-a-directory","errorCode":null,"errorMessage":"Path %s is a directory.","messagePattern":"Path (.+?) is a directory\\.","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":489,"sourceCode":"    @Override\n    public String getScheme() {\n        return \"sftp\";\n    }\n\n    @Override\n    public URI getUri() {\n        return uri;\n    }\n\n    @Override\n    public FSDataInputStream open(Path f, int bufferSize) throws IOException {\n        ChannelSftp channel = connect();\n        try {\n            Path workDir = new Path(channel.pwd());\n            Path absolute = makeAbsolute(workDir, f);\n            FileStatus fileStat = getFileStatus(channel, absolute);\n            if (fileStat.isDirectory()) {\n                throw new IOException(String.format(E_PATH_DIR, f));\n            }\n            // the path could be a symbolic link, so get the real path\n            absolute = new Path(\"/\", channel.realpath(absolute.toUri().getPath()));\n\n            InputStream is = channel.get(quote(absolute.toUri().getPath()));\n            return new FSDataInputStream(\n                    new SFTPInputStream(is, channel, connectionPool, statistics));\n        } catch (Exception e) {\n            disconnectAfterFailure(channel, e);\n            if (e instanceof IOException) {\n                throw (IOException) e;\n            }\n            throw new IOException(e);\n        }\n    }\n\n    /**\n     * A stream obtained via this call must be closed before using other APIs of this class or else","sourceCodeStart":471,"sourceCodeEnd":507,"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#L471-L507","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nFSDataInputStream in = fs.open(new Path(\"/data/in\"));\n// after\nPath p = new Path(\"/data/in\");\nif (fs.getFileStatus(p).isDirectory()) {\n    throw new IllegalArgumentException(\"Expected a file: \" + p);\n}\nFSDataInputStream in = fs.open(p);","handlingStrategy":"validation","validationCode":"Path p = new Path(\"/data/in/file.txt\");\nFileStatus st = fs.getFileStatus(p);\nif (st.isDirectory()) {\n    throw new IllegalArgumentException(\"Expected a file, got directory: \" + p);\n}","typeGuard":null,"tryCatchPattern":"try {\n    fs.open(p);\n} catch (IOException e) {\n    if (String.valueOf(e.getMessage()).contains(\"is a directory\")) {\n        // list dir and open children instead\n    } else { throw e; }\n}","preventionTips":["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"],"tags":["sftp","io","path"],"backgroundTag":"path-is-not-a-directory","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"}