{"record":{"id":"fb219d4d0d988b4b","repo":"apache/hadoop","slug":"cannot-rename-within-internal-dirs-of-mount-table","errorCode":null,"errorMessage":"Cannot Rename within internal dirs of mount table: src={} is readOnly","messagePattern":"Cannot Rename within internal dirs of mount table: src=(.+?) is readOnly","errorType":"exception","errorClass":"AccessControlException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java","lineNumber":580,"sourceCode":"      UnresolvedLinkException, IOException {\n    InodeTree.ResolveResult<AbstractFileSystem> res =\n        fsState.resolve(getUriPath(f), true);\n    return res.targetFileSystem.truncate(res.remainingPath, newLength);\n  }\n\n  @Override\n  public void renameInternal(final Path src, final Path dst,\n      final boolean overwrite) throws IOException, UnresolvedLinkException {\n    // passing resolveLastComponet as false to catch renaming a mount point\n    // itself we need to catch this as an internal operation and fail if no\n    // fallback.\n    InodeTree.ResolveResult<AbstractFileSystem> resSrc =\n        fsState.resolve(getUriPath(src), false);\n\n    if (resSrc.isInternalDir()) {\n      if (fsState.getRootFallbackLink() == null) {\n        // If fallback is null, we can't rename from src.\n        throw new AccessControlException(\n            \"Cannot Rename within internal dirs of mount table: src=\" + src\n                + \" is readOnly\");\n      }\n      InodeTree.ResolveResult<AbstractFileSystem> resSrcWithLastComp =\n          fsState.resolve(getUriPath(src), true);\n      if (resSrcWithLastComp.isInternalDir() || resSrcWithLastComp\n          .isLastInternalDirLink()) {\n        throw new AccessControlException(\n            \"Cannot Rename within internal dirs of mount table: src=\" + src\n                + \" is readOnly\");\n      } else {\n        // This is fallback and let's set the src fs with this fallback\n        resSrc = resSrcWithLastComp;\n      }\n    }\n\n    InodeTree.ResolveResult<AbstractFileSystem> resDst =\n        fsState.resolve(getUriPath(dst), false);","sourceCodeStart":562,"sourceCodeEnd":598,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java#L562-L598","documentation":"ViewFs.renameInternal resolves the source with resolveLastComponent=false to detect renames of mount points. When src resolves to an internal dir and no root fallback link (fs.viewfs.mounttable.<n>.linkFallback) is configured, there is no real FileSystem to rename from, so it throws AccessControlException(\"Cannot Rename within internal dirs of mount table: src=<src> is readOnly\").","triggerScenarios":"FileContext.rename(viewfs:///user/x, ...) where /user/x is a virtual container dir (mount links only below it) and no linkFallback is set; federation clients where admins deliberately omitted a fallback to keep the root immutable.","commonSituations":"Data-management jobs moving directories up/down a federated tree; tools coded against plain HDFS that rename from paths which exist only virtually in viewfs.","solutions":["Configure fs.viewfs.mounttable.<n>.linkFallback=<hdfs-uri> so renames from internal dirs fall through to a real cluster","Rename a concrete path inside a mount point instead of the virtual container","Catch AccessControlException and surface 'source is a read-only mount table node'"],"exampleFix":"<!-- before: no fallback, rename from virtual dir throws -->\n\n<!-- after (core-site.xml): enable fallback cluster -->\n<property><name>fs.viewfs.mounttable.c1.linkFallback</name>\n  <value>hdfs://nnFallback:8020/fallback</value></property>","handlingStrategy":"try-catch","validationCode":"// Validate src before rename: must resolve into a mount point or fallback must exist\nstatic boolean renameSrcOk(ViewFileSystem vfs, Path src) {\n  String s = src.toUri().getPath();\n  boolean mounted = vfs.getMountPoints().stream()\n      .anyMatch(mp -> s.startsWith(mp.getMountedOnPath() + \"/\") && !s.equals(mp.getMountedOnPath().toString()));\n  return mounted; // if false, a linkFallback must be configured for the rename to work\n}","typeGuard":null,"tryCatchPattern":"try {\n  fc.rename(src, dst, Rename.NONE);\n} catch (AccessControlException ace) {\n  if (ace.getMessage().contains(\"src=\") && ace.getMessage().contains(\"readOnly\")) {\n    // src is an internal dir and no linkFallback is set\n  }\n}","preventionTips":["Configure linkFallback when tools must rename from virtual dirs","Rename concrete subtrees inside mount points instead of container directories"],"tags":["viewfs","mount-table","rename","access-control","hadoop-common"],"backgroundTag":"viewfs-internal-dir-protected","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}