apache/hadoop · error · FileNotFoundException

'{}' is a directory

Error message

'{}' is a directory

What it means

open() stats the path and refuses directories with FileNotFoundException("'<path>' is a directory"). COS has no directory payload to read, so opening a directory key — including the 0-byte marker objects CosN itself creates — is treated as 'nothing to read', mirroring LocalFileSystem behavior.

Source

Thrown at hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNFileSystem.java:592

      if (LOG.isDebugEnabled()) {
        LOG.debug("Make directory: [{}] in COS.", f);
      }

      String folderPath = pathToKey(makeAbsolute(f));
      if (!folderPath.endsWith(PATH_DELIMITER)) {
        folderPath += PATH_DELIMITER;
      }
      store.storeEmptyFile(folderPath);
    }
    return true;
  }

  @Override
  public FSDataInputStream open(Path f, int bufferSize) throws IOException {
    FileStatus fs = getFileStatus(f); // will throw if the file doesn't
    // exist
    if (fs.isDirectory()) {
      throw new FileNotFoundException("'" + f + "' is a directory");
    }
    LOG.info("Open the file: [{}] for reading.", f);
    Path absolutePath = makeAbsolute(f);
    String key = pathToKey(absolutePath);
    long fileSize = store.getFileLength(key);
    return new FSDataInputStream(new BufferedFSInputStream(
        new CosNInputStream(this.getConf(), store, statistics, key, fileSize,
            this.boundedIOThreadPool), bufferSize));
  }

  @Override
  public boolean rename(Path src, Path dst) throws IOException {
    LOG.debug("Rename source path: [{}] to dest path: [{}].", src, dst);

    // Renaming the root directory is not allowed
    if (src.isRoot()) {
      LOG.debug("Cannot rename the root directory of a filesystem.");
      return false;

View on GitHub (pinned to 2add963021)

Solutions

  1. Filter glob results: only open statuses where isFile() is true.
  2. If a file was expected, inspect getFileStatus(p) — the path is actually a directory.
  3. Use fs.listStatus(dir) to enumerate children instead of open().

Example fix

// before
for (FileStatus s : fs.globStatus(new Path('/in/*'))) {
  FSDataInputStream in = fs.open(s.getPath()); // throws on directories
}

// after
for (FileStatus s : fs.globStatus(new Path('/in/*'))) {
  if (s.isFile()) {
    FSDataInputStream in = fs.open(s.getPath());
  }
}
Defensive patterns

Strategy: validation

Validate before calling

FileStatus st = fs.getFileStatus(p);
if (st.isDirectory()) {
  for (FileStatus child : fs.listStatus(p)) { /* enumerate instead of open */ }
} else {
  FSDataInputStream in = fs.open(p);
}

Type guard

static boolean isOpenableFile(FileStatus st) {
  return st.isFile();
}

Try / catch

try {
  return fs.open(p);
} catch (FileNotFoundException e) {
  if (e.getMessage() != null && e.getMessage().endsWith('is a directory')) {
    // caller passed a directory: fall back to listing
    return null; // or throw a clearer domain error
  }
  throw e;
}

Prevention

When it happens

Trigger: fs.open(dirPath); opening a path that exists only as an implicit directory (common prefixes derived from children); hadoop fs -cat on a directory; code that globs a pattern and open()s every result without filtering.

Common situations: Glob 'cosn://bucket/*' then open each status including directories; passing a directory to a reader that expects a file; trailing-slash confusion where a directory path is handed to open unchanged.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/93cb115d38b28925. Report an issue: GitHub.