apache/hadoop · error · PathIsDirectoryException

dst.toString()

Error message

dst.toString()

What it means

checkDest() throws PathIsDirectoryException(dst.toString()) when the resolved destination path on dstFS already exists as a directory and overwrite is false and there is no source name to join onto it (srcName == null). PathIsDirectoryException extends IOException, so it surfaces as a normal IO error from FileUtil.copy. The message body is just the destination path string. It means 'you asked to write a file where a directory stands'.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileUtil.java:621

      return true;
    }
  }

  private static Path checkDest(String srcName, FileSystem dstFS, Path dst,
      boolean overwrite) throws IOException {
    FileStatus sdst;
    try {
      sdst = dstFS.getFileStatus(dst);
    } catch (FileNotFoundException e) {
      sdst = null;
    }
    if (null != sdst) {
      if (sdst.isDirectory()) {
        if (null == srcName) {
          if (overwrite) {
            return dst;
          }
          throw new PathIsDirectoryException(dst.toString());
        }
        return checkDest(null, dstFS, new Path(dst, srcName), overwrite);
      } else if (!overwrite) {
        throw new PathExistsException(dst.toString(),
            "Target " + dst + " already exists");
      }
    }
    return dst;
  }

  public static boolean isRegularFile(File file) {
    return isRegularFile(file, true);
  }

  /**
   * Check if the file is regular.
   * @param file The file being checked.
   * @param allowLinks Whether to allow matching links.

View on GitHub (pinned to 2add963021)

Solutions

  1. Point the destination at a file path that does not collide with an existing directory (dst + '/filename')
  2. Delete or rename the conflicting directory on dstFS before copying
  3. Catch PathIsDirectoryException and either fail with a clear message or route to a new destination
  4. Use FileSystem.copyFromLocalFile(delSrc, overwrite, src, dst) when you want overwrite semantics instead of the hard-coded overwrite=false in this copy() overload

Example fix

// before
FileUtil.copy(new File("data.txt"), fs, new Path("/out/data.txt"), false, conf);
// throws PathIsDirectoryException when /out/data.txt is a directory

// after
Path dst = new Path("/out/data.txt");
FileStatus st = fs.exists(dst) ? fs.getFileStatus(dst) : null;
if (st != null && st.isDirectory()) {
  throw new IOException("Refusing to overwrite directory " + dst);
}
FileUtil.copy(new File("data.txt"), fs, dst, false, conf);
Defensive patterns

Strategy: validation

Validate before calling

Path dst = new Path("/out/data.txt");
if (dstFS.exists(dst) && dstFS.getFileStatus(dst).isDirectory()) {
  throw new IOException("Destination " + dst + " is a directory; refusing to copy file onto it");
}
FileUtil.copy(src, dstFS, dst, false, conf);

Try / catch

try {
  FileUtil.copy(src, dstFS, dst, false, conf);
} catch (PathIsDirectoryException e) {
  // dst resolves to an existing directory; pick a file-level destination
  dst = new Path(dst, src.getName());
  FileUtil.copy(src, dstFS, dst, false, conf);
}

Prevention

When it happens

Trigger: FileUtil.copy(File src, FileSystem dstFS, Path dst, false, conf) where dst (or dst/srcName via the recursive checkDest(null, ...) call) resolves to an existing directory; checkDest recursing into new Path(dst, srcName) that collides with a pre-existing subdirectory of the same name.

Common situations: Uploading a file named 'conf' into an HDFS dir that already contains a directory 'conf'; CI jobs re-running a put without -f semantics; passing an HDFS directory path as the file destination.

Related errors


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