{"record":{"id":"29cdc229944029a8","repo":"apache/hadoop","slug":"fs-s-namenode-id-collision-for-path-s-nnid-s-u","errorCode":null,"errorMessage":"FS:%s, Namenode ID collision for path:%s nnid:%s uri being added:%s existing uri:%s","messagePattern":"FS:(.+?), Namenode ID collision for path:(.+?) nnid:(.+?) uri being added:(.+?) existing uri:(.+?)","errorType":"exception","errorClass":"FileSystemException","httpStatus":null,"severity":"critical","filePath":"hadoop-hdfs-project/hadoop-hdfs-nfs/src/main/java/org/apache/hadoop/hdfs/nfs/nfs3/DFSClientCache.java","lineNumber":181,"sourceCode":"    String[] exportsPath =\n        config.getStrings(NfsConfigKeys.DFS_NFS_EXPORT_POINT_KEY,\n            NfsConfigKeys.DFS_NFS_EXPORT_POINT_DEFAULT);\n    for (String exportPath : exportsPath) {\n      URI exportURI = Nfs3Utils.getResolvedURI(fs, exportPath);\n      int namenodeId = Nfs3Utils.getNamenodeId(config, exportURI);\n      URI value = namenodeUriMap.get(namenodeId);\n      // if a unique nnid, add it to the map\n      if (value == null) {\n        LOG.info(\"Added export: {} FileSystem URI: {} with namenodeId: {}\",\n            exportPath, exportPath, namenodeId);\n        namenodeUriMap.put(namenodeId, exportURI);\n      } else if (!exportURI.getAuthority().equals(value.getAuthority())) {\n        // different namenode authorities hashed to the same namenodeId — real collision\n        String msg = String.format(\"FS:%s, Namenode ID collision for path:%s \"\n                + \"nnid:%s uri being added:%s existing uri:%s\", fs.getScheme(),\n            exportPath, namenodeId, exportURI, value);\n        LOG.error(msg);\n        throw new FileSystemException(msg);\n      } else {\n        // same namenode authority (multiple export paths on the same namenode) — safe\n        LOG.debug(\"Export path: {} maps to an already-registered namenode URI: {}\"\n            + \" with namenodeId: {}\", exportPath, exportURI, namenodeId);\n      }\n    }\n  }\n\n  /**\n   * Priority of the FileSystem shutdown hook.\n   */\n  public static final int SHUTDOWN_HOOK_PRIORITY = 10;\n  \n  private class CacheFinalizer implements Runnable {\n    @Override\n    public synchronized void run() {\n      try {\n        closeAll(true);","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs-nfs/src/main/java/org/apache/hadoop/hdfs/nfs/nfs3/DFSClientCache.java#L163-L199","documentation":"DFSClientCache registers each nfs.exports entry into namenodeUriMap keyed by namenodeId. When a new export resolves to a URI whose authority differs from the one already stored under the same namenodeId, two different NameNodes are claiming one identity — a real collision — and startup of the NFS gateway fails with this FileSystemException (the code comments call out the same-authority case as safe).","triggerScenarios":"Two nfs.exports entries that derive the same namenodeId but resolve to different NameNode host:port authorities: exporting paths from both a nameservice and a bare NameNode address of the same cluster, mixing HA nameservice IDs and standalone NN URIs, or misconfigured viewfs mount entries that point at different clusters.","commonSituations":"Copy-pasting nfs.exports entries between HA and non-HA cluster configs; adding a second export for a different cluster while reusing nameservice/namenode identifiers; mount-table entries whose target authorities disagree.","solutions":["Audit nfs.exports: every entry that maps to one namenodeId must resolve to the same NameNode authority.","Use consistent identifiers — either the HA nameservice ID (hdfs://ns1/...) or the exact same host:port — for all exports of one cluster.","Give the second, different NameNode a distinct id/entry so it cannot collide.","Fix the config and restart the NFS gateway; registration happens at Nfs3 startup."],"exampleFix":"# before (nfs.exports — same id, two different NameNodes)\n/clusterA hdfs://nnA1:8020 rw\n/clusterA hdfs://nnB1:8020 rw\n# after (distinct paths/authorities, consistent ids)\n/clusterA hdfs://nsA rw\n/clusterB hdfs://nsB rw","handlingStrategy":"validation","validationCode":"/* before registering exports, assert one id -> one authority */\nMap<String, URI> byId = new HashMap<>();\nfor (ExportEntry e : parseExports()) {\n    URI u = resolveUri(e);\n    URI prev = byId.putIfAbsent(namenodeIdOf(e), u);\n    if (prev != null && !u.getAuthority().equals(prev.getAuthority())) {\n        throw new IllegalStateException(\"Export config collision on \" + e.getPath());\n    }\n}","typeGuard":"private boolean exportsHaveUniqueNamenodeIds(List<ExportEntry> exports) {\n    Map<String, String> idToAuthority = new HashMap<>();\n    for (ExportEntry e : exports) {\n        String auth = resolveUri(e).getAuthority();\n        String prev = idToAuthority.putIfAbsent(namenodeIdOf(e), auth);\n        if (prev != null && !prev.equals(auth)) return false;\n    }\n    return true;\n}","tryCatchPattern":"try {\n    cache.putNamenodeUriKey(exportPath);\n} catch (FileSystemException e) {\n    // deterministic config error at startup: fail fast with the full message —\n    // it names the colliding path, id, and both URIs; fix nfs.exports and restart.\n    throw new ConfigurationException(\"nfs.exports namenodeId collision: \" + e.getMessage(), e);\n}","preventionTips":["Use one canonical authority (HA nameservice ID or single host:port) per exported cluster in nfs.exports.","Lint nfs.exports at deploy time: reject configs where the same export-derived id maps to different authorities.","Never mix nameservice-based and bare-host entries for the same cluster in nfs.exports.","Remember registration happens once at Nfs3 startup — always restart the gateway after fixing exports."],"tags":["nfs-gateway","hdfs","exports","dfsclientcache","startup","configuration"],"backgroundTag":"namenode-id-collision","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}