apache/hadoop · error · ParentNotDirectoryException

Can't make directory for path %s since it is a file.

Error message

Can't make directory for path %s since it is a file.

What it means

mkdirs() first checks whether the target exists; if it exists and is a regular file, creating a directory there is impossible and ParentNotDirectoryException is thrown — the standard Hadoop signal for 'a path component that must be a directory is a file'. Here the conflict is the target path itself.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ftp/FTPFileSystem.java:606

   * the overhead of opening/closing a TCP connection.
   */
  private boolean mkdirs(FTPClient client, Path file, FsPermission permission)
      throws IOException {
    boolean created = true;
    Path workDir = new Path(client.printWorkingDirectory());
    Path absolute = makeAbsolute(workDir, file);
    String pathName = absolute.getName();
    if (!exists(client, absolute)) {
      Path parent = absolute.getParent();
      created = (parent == null || mkdirs(client, parent, FsPermission
          .getDirDefault()));
      if (created) {
        String parentDir = parent.toUri().getPath();
        client.changeWorkingDirectory(parentDir);
        created = created && client.makeDirectory(pathName);
      }
    } else if (isFile(client, absolute)) {
      throw new ParentNotDirectoryException(String.format(
          "Can't make directory for path %s since it is a file.", absolute));
    }
    return created;
  }

  /**
   * Convenience method, so that we don't open a new connection when using this
   * method from within another method. Otherwise every API invocation incurs
   * the overhead of opening/closing a TCP connection.
   */
  private boolean isFile(FTPClient client, Path file) {
    try {
      return getFileStatus(client, file).isFile();
    } catch (FileNotFoundException e) {
      return false; // file does not exist
    } catch (IOException ioe) {
      throw new FTPException("File check failed", ioe);
    }

View on GitHub (pinned to 2add963021)

Solutions

  1. Remove the conflicting file first: if (fs.exists(p) && fs.getFileStatus(p).isFile()) fs.delete(p, false)
  2. Use distinct paths for file and directory artifacts instead of reusing the same string
  3. Catch ParentNotDirectoryException to fail with a message naming the conflicting path

Example fix

// before
fs.mkdirs(new Path("/data/out")); // /data/out exists as a file
// ParentNotDirectoryException

// after
Path p = new Path("/data/out");
if (fs.exists(p) && fs.getFileStatus(p).isFile()) {
  fs.delete(p, false);
}
fs.mkdirs(p);
Defensive patterns

Strategy: validation

Validate before calling

if (fs.exists(dir) && fs.getFileStatus(dir).isFile()) {
  fs.delete(dir, false); // clear the file conflicting with the directory path
}
boolean ok = fs.mkdirs(dir);

Type guard

static boolean isFreeForDirectory(FileSystem fs, Path p) throws IOException {
  return !fs.exists(p) || fs.getFileStatus(p).isDirectory();
}

Try / catch

try {
  fs.mkdirs(dir);
} catch (ParentNotDirectoryException e) {
  // a file occupies the path: surface which path conflicted instead of a generic failure
  throw new IOException("Path conflicts with an existing file: " + dir, e);
}

Prevention

When it happens

Trigger: fs.mkdirs(path) where path already exists as a file; checkpoint/restart directories whose path was previously an output file; create-then-mkdirs ordering bugs in job setup.

Common situations: Reusing one path for different artifact types between runs; logic changes that turn a file path into a directory path; incomplete cleanup after a failed run leaves a file where a directory is now expected.

Related errors


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