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
- Choose a destination whose parent is a directory; verify with `hdfs dfs -test -d <parent>`.
- Remove or rename the blocking file if it is stale.
- 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
- Build destinations with Path(parent, name) instead of string concatenation.
- Test -d the destination parent in shell scripts before mv.
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
- rename destination parent {} not found.
- rename destination parent ${parent} is a file.
- {} doesn't support renameSnapshot
- Is not a directory
- Could not rename {oldDir} to {newDir}
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/75e889cb35f80439.
Report an issue: GitHub.