{"record":{"id":"d41a04ca62dc24e1","repo":"apache/hadoop","slug":"cannnot-build-location-should-not-resolve-mult","errorCode":null,"errorMessage":"Cannnot build location, {} should not resolve multiple destinations for {}","messagePattern":"Cannnot build location, (.+?) should not resolve multiple destinations for (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/resolver/MountTableResolver.java","lineNumber":593,"sourceCode":"\n  /**\n   * Build a location for this result beneath the discovered mount point.\n   *\n   * @param path Path to build for.\n   * @param entry Mount table entry.\n   * @return PathLocation containing the namespace, local path.\n   */\n  private PathLocation buildLocation(\n      final String path, final MountTable entry) throws IOException {\n    String srcPath = entry.getSourcePath();\n    if (!path.startsWith(srcPath)) {\n      LOG.error(\"Cannot build location, {} not a child of {}\", path, srcPath);\n      return null;\n    }\n\n    List<RemoteLocation> dests = entry.getDestinations();\n    if (getClass() == MountTableResolver.class && dests.size() > 1) {\n      throw new IOException(\"Cannnot build location, \"\n          + getClass().getSimpleName()\n          + \" should not resolve multiple destinations for \" + path);\n    }\n\n    String remainingPath = path.substring(srcPath.length());\n    if (remainingPath.startsWith(Path.SEPARATOR)) {\n      remainingPath = remainingPath.substring(1);\n    }\n\n    List<RemoteLocation> locations = new LinkedList<>();\n    for (RemoteLocation oneDst : dests) {\n      String nsId = oneDst.getNameserviceId();\n      String dest = oneDst.getDest();\n      String newPath = dest;\n      if (!newPath.endsWith(Path.SEPARATOR) && !remainingPath.isEmpty()) {\n        newPath += Path.SEPARATOR;\n      }\n      newPath += remainingPath;","sourceCodeStart":575,"sourceCodeEnd":611,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/resolver/MountTableResolver.java#L575-L611","documentation":"The plain MountTableResolver supports only single-destination mounts: buildLocation() throws IOException (note the 'Cannnot' typo in the source) when the deepest mount entry for a path has more than one remote destination and the resolver's exact class is MountTableResolver. The getClass() == MountTableResolver.class check exempts subclasses — the router's RouterMountTableResolver, which applies destination ordering (HASH, LOCAL, ...), handles multi-destination entries.","triggerScenarios":"A mount added with multiple destinations (hdfs dfsrouteradmin -add /x -ns ns0 -dst /x -ns ns1 -dst /x -order HASH) is resolved through the default MountTableResolver — which happens when dfs.federation.router.file.resolver.client.class is left at its default (MountTableResolver) on a router, or in embedded/tool usage of the plain resolver.","commonSituations":"Introducing multi-destination load-balancing mounts into a federation whose routers still use the default file resolver class; standalone tools resolving paths against upgraded mount tables.","solutions":["Set dfs.federation.router.file.resolver.client.class to org.apache.hadoop.hdfs.server.federation.router.RouterMountTableResolver on the router and restart it","Or collapse the mount to a single destination: hdfs dfsrouteradmin -update /x -ns ns0 -dst /x","Verify with hdfs dfsrouteradmin -list that all mounts are compatible with the configured resolver"],"exampleFix":"<!-- before: default resolver rejects multi-destination mounts -->\n<property>\n  <name>dfs.federation.router.file.resolver.client.class</name>\n  <value>org.apache.hadoop.hdfs.server.federation.resolver.MountTableResolver</value>\n</property>\n<!-- after -->\n<property>\n  <name>dfs.federation.router.file.resolver.client.class</name>\n  <value>org.apache.hadoop.hdfs.server.federation.router.RouterMountTableResolver</value>\n</property>","handlingStrategy":"validation","validationCode":"// Reject multi-destination mounts when running the plain resolver\nboolean plain = resolver.getClass() == MountTableResolver.class;\nfor (MountTable e : resolver.getMounts(\"/\")) {\n  if (plain && e.getDestinations().size() > 1) {\n    throw new IOException(\"Mount \" + e.getSourcePath()\n        + \" has multiple destinations; configure RouterMountTableResolver\");\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Standardize routers on RouterMountTableResolver once any mount has >1 destination","Validate the mount table (-list) against the configured resolver class after admin changes","Set dfs.federation.router.file.resolver.client.class explicitly in router configs rather than relying on the default"],"tags":["hadoop","rbf","mount-table","resolver","multi-destination","configuration"],"backgroundTag":"unsupported-multi-destination-route","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}