{"record":{"id":"b5233e8bdd1b82ed","repo":"apache/hadoop","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":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/sftp/SFTPFileSystem.java","lineNumber":520,"sourceCode":"  @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    Path workDir;\n    try {\n      workDir = new Path(channel.pwd());\n    } catch (SftpException e) {\n      throw new IOException(e);\n    }\n    Path absolute = makeAbsolute(workDir, f);\n    FileStatus fileStat = getFileStatus(channel, absolute);\n    if (fileStat.isDirectory()) {\n      disconnect(channel);\n      throw new IOException(String.format(E_PATH_DIR, f));\n    }\n    try {\n      // the path could be a symbolic link, so get the real path\n      absolute = new Path(\"/\", channel.realpath(absolute.toUri().getPath()));\n    } catch (SftpException e) {\n      throw new IOException(e);\n    }\n    return new FSDataInputStream(\n        new SFTPInputStream(channel, absolute, statistics)){\n      @Override\n      public void close() throws IOException {\n        try {\n          super.close();\n        } finally {\n          disconnect(channel);\n        }\n      }\n    };","sourceCodeStart":502,"sourceCodeEnd":538,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/sftp/SFTPFileSystem.java#L502-L538","documentation":"Thrown by SFTPFileSystem.open(Path f, int bufferSize) when getFileStatus on the resolved path reports a directory. Opening a read stream against a directory is not meaningful over SFTP, so the adapter disconnects the channel and throws IOException(E_PATH_DIR).","triggerScenarios":"Calling fs.open(f) (directly or via open(f, bufferSize)) on an sftp:// path whose lstat attributes have the directory bit set; typically a variable, glob, or config property that points at a directory rather than a file.","commonSituations":"A reader configured with a job input directory instead of a specific file; a path variable that resolved to the parent directory; code that assumed open() on a directory would fail differently (e.g., FileNotFoundException) or return an empty stream.","solutions":["Guard the open with a file check: if (!fs.getFileStatus(f).isFile()) fail fast with your own message.","If the intent was to enumerate contents, use fs.listStatus(dir) instead of open().","Validate configuration-supplied input paths at application startup (isFile) before any stream is opened."],"exampleFix":"// before\nFSDataInputStream in = fs.open(inputPath); // throws if inputPath is a directory\n\n// after\nFileStatus st = fs.getFileStatus(inputPath);\nif (st.isDirectory()) {\n  throw new IllegalArgumentException(\"input must be a file: \" + inputPath);\n}\nFSDataInputStream in = fs.open(inputPath);","handlingStrategy":"validation","validationCode":"FileStatus st = fs.getFileStatus(f);\nif (st.isDirectory()) {\n  throw new IllegalArgumentException(\"expected a file, got directory: \" + f);\n}\nFSDataInputStream in = fs.open(f);","typeGuard":"private static boolean isRegularFile(FileSystem fs, Path p) throws IOException {\n  FileStatus st = fs.getFileStatus(p);\n  return !st.isDirectory();\n}","tryCatchPattern":"try {\n  in = fs.open(f);\n} catch (IOException e) {\n  if (e.getMessage() != null && e.getMessage().endsWith(\"is a directory.\")) {\n    // input path points at a directory -> fix configuration\n  } else {\n    throw e;\n  }\n}","preventionTips":["Validate configured input paths once at startup with getFileStatus(...).isFile().","Use listStatus() for enumeration; reserve open() for files."],"tags":["sftp","open","directory-path","hadoop","filesystem"],"backgroundTag":"open-on-directory","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}