apache/hadoop · error · IOException

Source '{srcFile}' exists but is a directory

Error message

Source '{srcFile}' exists but is a directory

What it means

Guard clause of Storage.nativeCopyFileUnbuffered: srcFile exists but isDirectory() is true. The helper copies a single regular file with OS unbuffered IO; directories are rejected so NativeIO.copyFileUnbuffered never receives a directory handle.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/common/Storage.java:1336

   *  should be the same as the original
   *
   * @throws NullPointerException if source or destination is {@code null}
   * @throws IOException if source or destination is invalid
   * @throws IOException if an IO error occurs during copying
   */
  public static void nativeCopyFileUnbuffered(File srcFile, File destFile,
      boolean preserveFileDate) throws IOException {
    if (srcFile == null) {
      throw new NullPointerException("Source must not be null");
    }
    if (destFile == null) {
      throw new NullPointerException("Destination must not be null");
    }
    if (srcFile.exists() == false) {
      throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
    }
    if (srcFile.isDirectory()) {
      throw new IOException("Source '" + srcFile + "' exists but is a directory");
    }
    if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) {
      throw new IOException("Source '" + srcFile + "' and destination '" +
          destFile + "' are the same");
    }
    File parentFile = destFile.getParentFile();
    if (parentFile != null) {
      if (!parentFile.mkdirs() && !parentFile.isDirectory()) {
        throw new IOException("Destination '" + parentFile
            + "' directory cannot be created");
      }
    }
    if (destFile.exists()) {
      if (FileUtil.canWrite(destFile) == false) {
        throw new IOException("Destination '" + destFile
            + "' exists but is read-only");
      } else {
        if (destFile.delete() == false) {

View on GitHub (pinned to 2add963021)

Solutions

  1. Point the copy at the file inside the directory
  2. If a whole directory must be copied, walk its entries and copy each file (e.g. FileUtil.copy) rather than this single-file API

Example fix

// before
Storage.nativeCopyFileUnbuffered(new File("/nn/current"), dst, true);
// after
Storage.nativeCopyFileUnbuffered(new File("/nn/current/fsimage_0001"), dst, true);
Defensive patterns

Strategy: validation

Validate before calling

if (srcFile != null && srcFile.isDirectory()) {
  throw new IOException("expected a file but got directory: " + srcFile.getAbsolutePath());
}

Type guard

static boolean isFileNotDirectory(File f) {
  return f != null && f.isFile() && !f.isDirectory();
}

Prevention

When it happens

Trigger: The source path points at a directory (e.g. the checkpoint directory instead of the fsimage inside it); a glob or config value expanded to a directory; a path where the expected file was replaced by a same-named directory.

Common situations: Configuring a copy source with a directory-level setting instead of the file; tests with fixture layout mismatches; scripts that pass dirname instead of a file path.

Related errors


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