apache/hadoop · error · IOException
Failed to rename %s to %s, %s is a file
Error message
Failed to rename %s to %s, %s is a file
What it means
ZombieCluster.buildCluster() walks the LoggedNetworkTopology tree and requires every leaf to sit at the same depth; the first time it finds a leaf at a different depth than an earlier leaf it throws IllegalArgumentException. Depth matters because rumen hard-codes the bottom two levels as RackNode -> MachineNode (see 'path[level-1].addChild(current)' and the RackNode/MachineNode split in the second pass), so an unbalanced tree would misassign machine/rack roles. This is a data-quality contract on the topology JSON.
Source
Thrown at hadoop-cloud-storage-project/hadoop-bos/src/main/java/org/apache/hadoop/fs/bos/BaiduBosFileSystem.java:776
FileStatus dstStatus;
try {
dstStatus = getFileStatus(dstPath);
} catch (FileNotFoundException fnde) {
dstStatus = null;
}
if (dstStatus == null) {
Path dstParent = dstPath.getParent();
if (dstParent != null) {
Path currentPath = dstParent;
while (currentPath != null
&& !currentPath.isRoot()) {
FileStatus ancestorStatus;
try {
ancestorStatus = getFileStatus(currentPath);
if (!ancestorStatus.isDirectory()) {
throw new IOException(String.format(
"Failed to rename %s to %s, %s is a file",
srcPath, dstPath, currentPath));
}
break;
} catch (FileNotFoundException fnde) {
currentPath = currentPath.getParent();
}
}
}
LOG.debug("Parent directory {} does not exist "
+ "or will be implicitly created during rename",
dstPath.getParent());
} else {
if (dstStatus.isDirectory()) {
dstPath = new Path(dstPath, srcPath.getName());
FileStatus status;
try {
status = getFileStatus(dstPath);View on GitHub (pinned to 2add963021)
Solutions
- Normalize the topology JSON so every path from root to leaf has the same number of levels (standard: root -> rack -> host).
- Locate the imbalance by printing each leaf's depth from the LoggedNetworkTopology tree before constructing ZombieCluster (a 10-line DFS makes the offending branch obvious).
- Remove empty/placeholder children entries — an entry with no children is a leaf and any depth mismatch counts.
- For genuinely deeper topologies, flatten intermediate switches into rack names (rack/switch naming) to keep the two-level rack/host model.
Example fix
// before (topology.json): unbalanced
// { "name":"/dc", "children":[
// { "name":"/r1", "children":[ {"name":"h1"} ] },
// { "name":"/r2", "children":[
// { "name":"/sw", "children":[ {"name":"h2"} ] } ] } ] }
new ZombieCluster(topology, defaultNode); // IllegalArgumentException
// after (topology.json): balanced root -> rack -> host
// { "name":"/dc", "children":[
// { "name":"/r1", "children":[ {"name":"h1"} ] },
// { "name":"/r2", "children":[ {"name":"h2"} ] } ] }
new ZombieCluster(topology, defaultNode); Defensive patterns
Strategy: validation
Validate before calling
// Verify all leaves share one depth BEFORE building the ZombieCluster
static int checkBalanced(LoggedNetworkTopology n, int depth, Integer leafDepth,
java.util.List<String> badLeaves) {
List<LoggedNetworkTopology> kids = n.getChildren();
if (kids == null || kids.isEmpty()) {
if (leafDepth != null && leafDepth != depth) badLeaves.add(n.getName().getValue());
return leafDepth == null ? depth : leafDepth;
}
for (LoggedNetworkTopology c : kids) leafDepth = checkBalanced(c, depth + 1, leafDepth, badLeaves);
return leafDepth;
}
// if (!badLeaves.isEmpty()) fail with the offending leaf names Try / catch
try {
cluster = new ZombieCluster(topology, defaultNode);
} catch (IllegalArgumentException e) {
if ("Leaf nodes are not on the same level".equals(e.getMessage())) {
throw new IOException("Topology file has unbalanced depth; normalize to root/rack/host", e);
}
throw e;
} Prevention
- Keep topology JSONs at a fixed three-layer shape: root -> rack -> host.
- Automate a balance check in your topology-export pipeline.
- Watch for empty children arrays: they create accidental leaves.
When it happens
Trigger: new ZombieCluster(topology, defaultNode) where one branch of the topology ends at depth 1 and another at depth 2 — e.g. one rack entry has bare host children while another has an intermediate switch layer; feeding ClusterTopologyReader a topology file with a stray empty node; hand-authored topology JSON with inconsistent nesting.
Common situations: Editing a rumen topology JSON by hand and forgetting a level; combining topology dumps from different cluster generations; clusters modeled with per-rack switch hierarchies only in part of the datacenter.
Related errors
- Can not open a folder
- Failed to rename %s to %s, file already exists or not empty!
- Truncate is not supported by BaiduBosFileSystem
- user accessKey and secretAccessKey should not be null
- NoSuchUpload
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/284d7b39eebbe61c.
Report an issue: GitHub.