{"record":{"id":"c06297443952657f","repo":"apache/hadoop","slug":"path-nextinode-fullpath-already-exists-as-link","errorCode":null,"errorMessage":"Path {nextInode.fullPath} already exists as link","messagePattern":"Path (.+?) already exists as link","errorType":"validation","errorClass":"FileAlreadyExistsException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/InodeTree.java","lineNumber":458,"sourceCode":"    int i;\n    // Ignore first initial slash, process all except last component\n    for (i = 1; i < srcPaths.length - 1; i++) {\n      final String iPath = srcPaths[i];\n      INode<T> nextInode = curInode.resolveInternal(iPath);\n      if (nextInode == null) {\n        INodeDir<T> newDir = curInode.addDir(iPath, aUgi);\n        newDir.setInternalDirFs(getTargetFileSystem(newDir));\n        nextInode = newDir;\n      }\n      if (!nextInode.isInternalDir()) {\n        if (isNestedMountPointSupported) {\n          // nested mount detected, add a new INodeDirLink that wraps existing INodeLink to INodeTree and override existing INodelink\n          INodeDirLink<T> dirLink = new INodeDirLink<T>(nextInode.fullPath, aUgi, (INodeLink<T>) nextInode);\n          curInode.addDirLink(iPath, dirLink);\n          curInode = dirLink;\n        } else {\n          // Error - expected a dir but got a link\n          throw new FileAlreadyExistsException(\"Path \" + nextInode.fullPath +\n              \" already exists as link\");\n        }\n      } else {\n        assert(nextInode.isInternalDir());\n        curInode = (INodeDir<T>) nextInode;\n      }\n    }\n\n    // Now process the last component\n    // Add the link in 2 cases: does not exist or a link exists\n    String iPath = srcPaths[i];// last component\n    if (curInode.resolveInternal(iPath) != null) {\n      //  directory/link already exists\n      StringBuilder strB = new StringBuilder(srcPaths[0]);\n      for (int j = 1; j <= i; ++j) {\n        strB.append('/').append(srcPaths[j]);\n      }\n      throw new FileAlreadyExistsException(\"Path \" + strB +","sourceCodeStart":440,"sourceCodeEnd":476,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/InodeTree.java#L440-L476","documentation":"While inserting a mount, InodeTree walks the source path components. If an intermediate component already resolves to a link and the file system does not support nested mounts (isNestedMountPointSupported=false), it throws FileAlreadyExistsException('Path <path> already exists as link'). With nested-mount support the tree instead wraps the existing link in an INodeDirLink.","triggerScenarios":"Two mount entries where one source is a prefix of the other — e.g. link./user=... and link./user/data=... — on a ViewFileSystem built without nested mount support.","commonSituations":"Growing a federation mount table over time until mounts overlap; merging mount tables from two clusters; adding sub-directory mounts beneath existing mounts.","solutions":["Remove or restructure overlapping mounts so no mount source sits under another mount","Use a Hadoop build/config where nested mount points are supported (isNestedMountPointSupported=true)","Replace the parent single link with linkMerge so children remain resolvable"],"exampleFix":"<!-- before: /user/data nested under mounted /user -->\n<property><name>fs.viewfs.mounttable.cluster.link./user</name>\n  <value>hdfs://nnA/user</value></property>\n<property><name>fs.viewfs.mounttable.cluster.link./user/data</name>\n  <value>hdfs://nnB/data</value></property>\n\n<!-- after: single mount; data reached through nnA -->\n<property><name>fs.viewfs.mounttable.cluster.link./user</name>\n  <value>hdfs://nnA/user</value></property>","handlingStrategy":"try-catch","validationCode":"static boolean hasNestedMounts(Collection<String> srcs) {\n  List<String> sorted = new ArrayList<>(srcs);\n  Collections.sort(sorted);\n  for (int i = 1; i < sorted.size(); i++) {\n    if (sorted.get(i).startsWith(sorted.get(i - 1) + \"/\")) {\n      return true;\n    }\n  }\n  return false;\n}","typeGuard":null,"tryCatchPattern":"Catch FileAlreadyExistsException at ViewFileSystem init; 'already exists as link' identifies an overlapping mount — sort the mount sources and remove or restructure the nested one.","preventionTips":["Keep mount sources non-overlapping","Deduplicate and sort mount keys when generating config","Enable nested-mount support only on Hadoop versions that implement it"],"tags":["hadoop","viewfs","mount-table","configuration","conflict"],"backgroundTag":"mount-point-conflict","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}