apache/hadoop · error · AccessControlException
Cannot Rename within internal dirs of mount table: dest={} i
Error message
Cannot Rename within internal dirs of mount table: dest={} is readOnly What it means
The destination half of ViewFs.renameInternal: when dst resolves (with resolveLastComponent=false) to an internal dir and no root fallback link is configured, there is no target FileSystem to receive the rename, so it throws AccessControlException("Cannot Rename within internal dirs of mount table: dest=<dst> is readOnly"). With a fallback configured, the code instead tries resolving dst with the last component to allow renames that land under the fallback (see comment in source).
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java:603
fsState.resolve(getUriPath(src), true);
if (resSrcWithLastComp.isInternalDir() || resSrcWithLastComp
.isLastInternalDirLink()) {
throw new AccessControlException(
"Cannot Rename within internal dirs of mount table: src=" + src
+ " is readOnly");
} else {
// This is fallback and let's set the src fs with this fallback
resSrc = resSrcWithLastComp;
}
}
InodeTree.ResolveResult<AbstractFileSystem> resDst =
fsState.resolve(getUriPath(dst), false);
if (resDst.isInternalDir()) {
if (fsState.getRootFallbackLink() == null) {
// If fallback is null, we can't rename to dst.
throw new AccessControlException(
"Cannot Rename within internal dirs of mount table: dest=" + dst
+ " is readOnly");
}
// if the fallback exist, we may have chance to rename to fallback path
// where dst parent is matching to internalDir.
InodeTree.ResolveResult<AbstractFileSystem> resDstWithLastComp =
fsState.resolve(getUriPath(dst), true);
if (resDstWithLastComp.isInternalDir()) {
// We need to get fallback here. If matching fallback path not exist, it
// will fail later. This is a very special case: Even though we are on
// internal directory, we should allow to rename, so that src files will
// moved under matching fallback dir.
resDst = new InodeTree.ResolveResult<AbstractFileSystem>(
InodeTree.ResultKind.INTERNAL_DIR,
fsState.getRootFallbackLink().getTargetFileSystem(), "/",
new Path(resDstWithLastComp.resolvedPath), false);
} else {
// The link resolved to some target fs or fallback fs.View on GitHub (pinned to 2add963021)
Solutions
- Configure fs.viewfs.mounttable.<n>.linkFallback so dest falls through to a real cluster
- Add an explicit mount link for the destination parent (fs.viewfs.mounttable.<n>.link./archive)
- Rename to a concrete path inside an existing mount point
Example fix
<!-- before: rename to /archive (virtual) throws --> <!-- after (core-site.xml) --> <property><name>fs.viewfs.mounttable.c1.link./archive</name> <value>hdfs://nnArchive:8020/archive</value></property>
Defensive patterns
Strategy: try-catch
Validate before calling
static boolean renameDstOk(ViewFileSystem vfs, Path dst) {
String s = dst.toUri().getPath();
if (s.equals("/")) return false;
return vfs.getMountPoints().stream()
.map(mp -> mp.getMountedOnPath().toUri().getPath())
.anyMatch(m -> s.startsWith(m.endsWith("/") ? m : m + "/")); // false -> needs linkFallback or a new link
} Try / catch
try {
fc.rename(src, dst, Rename.NONE);
} catch (AccessControlException ace) {
if (ace.getMessage().contains("dest=") && ace.getMessage().contains("readOnly")) {
// dest resolves to internal dir without fallback: add linkFallback or link the dest parent
}
} Prevention
- Archive targets should be explicitly mounted parents, not virtual containers
- Set linkFallback so destinations outside mount points still resolve
When it happens
Trigger: FileContext.rename(src, viewfs:///archive, ...) where /archive is a virtual container with links only beneath it and linkFallback is unset; tools archiving data to federated parent dirs that the mount table does not mount directly.
Common situations: Archive/rotation jobs writing to directory levels that exist only virtually; same federation clients as errors 993/994 — the src side was fixed via fallback but dst now fails, or vice versa.
Related errors
- Cannot Rename within internal dirs of mount table: src={} is
- Cannot delete internal mount table directory: {}
- getXAttrs on path `{}' is not within a mount point
- listXAttrs on path `{}' is not within a mount point
- getQuotaUsage on path `{}' is not within a mount point
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/0323155f940997aa.
Report an issue: GitHub.