apache/hadoop · error · ParentNotDirectoryException

rename destination parent {} is a file.

Error message

rename destination parent {} is a file.

What it means

ParentNotDirectoryException when the destination's parent exists but is a regular file - a file cannot contain children, so the destination name is unreachable. This is checked immediately after the parent-not-found case, under the same destination validation.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirRenameOp.java:430

    final INode dstInode = dstIIP.getLastINode();
    List<INodeDirectory> dstSnapshottableDirs = new ArrayList<>();
    if (dstInode != null) { // Destination exists
      validateOverwrite(src, dst, overwrite, srcInode, dstInode);
      FSDirSnapshotOp.checkSnapshot(fsd, dstIIP, dstSnapshottableDirs);
    }

    INode dstParent = dstIIP.getINode(-2);
    if (dstParent == null) {
      error = "rename destination parent " + dst + " not found.";
      NameNode.stateChangeLog.warn("DIR* FSDirectory.unprotectedRenameTo: " +
          error);
      throw new FileNotFoundException(error);
    }
    if (!dstParent.isDirectory()) {
      error = "rename destination parent " + dst + " is a file.";
      NameNode.stateChangeLog.warn("DIR* FSDirectory.unprotectedRenameTo: " +
          error);
      throw new ParentNotDirectoryException(error);
    }

    validateNestSnapshot(fsd, src,
            dstParent.asDirectory(), srcSnapshottableDirs);
    checkUnderSameSnapshottableRoot(fsd, srcIIP, dstIIP);

    // Ensure dst has quota to accommodate rename
    verifyFsLimitsForRename(fsd, srcIIP, dstIIP);
    Pair<Optional<QuotaCounts>, Optional<QuotaCounts>> quotaPair =
        verifyQuotaForRename(fsd, srcIIP, dstIIP);

    RenameOperation tx = new RenameOperation(fsd, srcIIP, dstIIP, quotaPair);

    boolean undoRemoveSrc = true;
    tx.removeSrc();

    boolean undoRemoveDst = false;
    long removedNum = 0;

View on GitHub (pinned to 2add963021)

Solutions

  1. Choose a destination whose parent is a directory; verify with `hdfs dfs -test -d <parent>`.
  2. Remove or rename the blocking file if it is stale.
  3. Use Path.getParent()/Path suffix composition instead of string concatenation.

Example fix

# before
hdfs dfs -mv /staging/part /out.bin/part   # /out.bin is a file

# after
hdfs dfs -mv /staging/part /out-dir/part   # or mkdir -p /out-dir first
Defensive patterns

Strategy: type-guard

Validate before calling

Path parent = dst.getParent();
if (fs.exists(parent) && !fs.getFileStatus(parent).isDirectory()) {
  throw new ParentNotDirectoryException(parent + " is a file; choose a directory parent");
}
fs.rename(src, dst);

Type guard

static boolean parentIsDirectory(FileSystem fs, Path p) throws IOException {
  Path parent = p.getParent();
  return parent == null || parent.isRoot()
      || !fs.exists(parent) || fs.getFileStatus(parent).isDirectory();
}

Try / catch

try {
  fs.rename(src, dst);
} catch (ParentNotDirectoryException e) {
  // the message names the file acting as parent; fix dst construction and retry
  throw e;
}

Prevention

When it happens

Trigger: `hdfs dfs -mv /src /somefile/child` where /somefile is a file; destination built as parentPath + '/' + name where parentPath actually denotes a file; extension handling that leaves the file name in the parent slot.

Common situations: String-built destinations that confuse the parent component; paths where a file shadows an intended directory; templating bugs in ingest jobs.

Related errors


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