apache/hadoop · error · IOException
Rename destination {} is a directory or file under source {}
Error message
Rename destination {} is a directory or file under source {} What it means
IOException when the destination lies strictly inside the source subtree: dst.startsWith(src) and the character right after src is '/'. Moving a directory into itself is structurally impossible, so validateDestination rejects it. The separator check matters: src=/a does not block dst=/ab, only dst=/a/... - replicate exactly this check when pre-validating.
Source
Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirRenameOp.java:558
}
private static void validateDestination(
String src, String dst, INode srcInode)
throws IOException {
String error;
if (srcInode.isSymlink() &&
dst.equals(srcInode.asSymlink().getSymlinkString())) {
throw new FileAlreadyExistsException("Cannot rename symlink " + src
+ " to its target " + dst);
}
// dst cannot be a directory or a file under src
if (dst.startsWith(src)
&& dst.charAt(src.length()) == Path.SEPARATOR_CHAR) {
error = "Rename destination " + dst
+ " is a directory or file under source " + src;
NameNode.stateChangeLog.warn("DIR* FSDirectory.unprotectedRenameTo: "
+ error);
throw new IOException(error);
}
if (FSDirectory.isExactReservedName(src)
|| FSDirectory.isExactReservedName(dst)) {
error = "Cannot rename to or from /.reserved";
throw new InvalidPathException(error);
}
}
private static void validateOverwrite(
String src, String dst, boolean overwrite, INode srcInode, INode dstInode)
throws IOException {
String error;// It's OK to rename a file to a symlink and vice versa
if (dstInode.isDirectory() != srcInode.isDirectory()) {
error = "Source " + src + " and destination " + dst
+ " must both be directories";
NameNode.stateChangeLog.warn("DIR* FSDirectory.unprotectedRenameTo: "
+ error);View on GitHub (pinned to 2add963021)
Solutions
- Move to a sibling or outside the subtree: `hdfs dfs -mv /data /data_archive` (or /archive/data).
- If nesting is the end state, rename the parent elsewhere first, then restructure.
- Pre-validate: reject dst equal to src or starting with src + '/'.
Example fix
# before hdfs dfs -mv /data /data/archive # IOException: destination under source # after hdfs dfs -mv /data /archive/data
Defensive patterns
Strategy: validation
Validate before calling
static boolean isStrictlyUnder(String ancestor, String path) {
return path.length() > ancestor.length()
&& path.startsWith(ancestor)
&& path.charAt(ancestor.length()) == '/';
}
String s = src.toUri().getPath();
String d = dst.toUri().getPath();
if (s.equals(d) || isStrictlyUnder(s, d)) {
throw new IOException("Destination is inside the source subtree: " + d);
}
fs.rename(src, dst); Try / catch
try {
fs.rename(src, dst);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("under source")) {
// move to a sibling path instead, e.g. dst = new Path(src.getParent(), archiveName)
}
throw e;
} Prevention
- Compute archive destinations as siblings of the source, never as children.
- Mirror the NameNode's exact check (startsWith + '/' separator) in path validators.
When it happens
Trigger: `hdfs dfs -mv /data /data/archive`; destination built as src + '/' + suffix; archiving a directory into its own child; configs where the archive root defaults to inside the source tree.
Common situations: Archive-in-place patterns (the archive must be a sibling or outside path); templated destinations that accidentally prefix the source; rotation scripts computing dst from src components.
Related errors
- The source {} and destination {} are the same
- rename destination cannot be the root
- Invalid parameter value: destination = "{str}" is not an abs
- A file cannot be created in root.
- Rename to subdir is forbidden
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/b868cc3e8039b5cd.
Report an issue: GitHub.