apache/hadoop · error · IOException

Failed to rename since it is prohibited to rename dest path

Error message

Failed to rename since it is prohibited to rename dest path %s under src path %s

What it means

Thrown by the rename-destination validation in RawFileSystem when the final destination path is inside the source subtree (RawFSUtils.inSubtree(src, finalDstPath) is true). Renaming a directory into its own descendant would create a cycle, so the operation is rejected before any storage call.

Source

Thrown at hadoop-cloud-storage-project/hadoop-tos/src/main/java/org/apache/hadoop/fs/tosfs/RawFileSystem.java:306

    return true;
  }

  private Path checkAndGetDstPath(Path src, Path dest) throws IOException {
    FileStatus destStatus = getFileStatusOrNull(dest);
    // 1. Rebuilding the destination path
    Path finalDstPath = dest;
    if (destStatus != null && destStatus.isDirectory()) {
      finalDstPath = new Path(dest, src.getName());
    }

    // 2. No need to check the dest path because renaming itself is allowed.
    if (src.equals(finalDstPath)) {
      return finalDstPath;
    }

    // 3. Ensure the source path cannot be the ancestor of destination path.
    if (RawFSUtils.inSubtree(src, finalDstPath)) {
      throw new IOException(String.format("Failed to rename since it is prohibited to " +
          "rename dest path %s under src path %s", finalDstPath, src));
    }

    // 4. Ensure the destination path doesn't exist.
    FileStatus finalDstStatus = destStatus;
    if (destStatus != null && destStatus.isDirectory()) {
      finalDstStatus = getFileStatusOrNull(finalDstPath);
    }
    if (finalDstStatus != null) {
      throw new FileAlreadyExistsException(
          String.format("Failed to rename since the dest path %s already exists.", finalDstPath));
    } else {
      return finalDstPath;
    }
  }

  private FileStatus checkAndGetSrcStatus(Path src) throws IOException {
    // throw FileNotFoundException if src not found.

View on GitHub (pinned to 2add963021)

Solutions

  1. Choose a destination outside the source subtree, e.g. rename('/a/b', '/a/c') instead of rename('/a/b', '/a/b/c')
  2. If the intent is to move under a sibling directory, target the sibling: rename('/a/b', '/a-dst/b')
  3. Validate before calling: reject when dest.isDescendant(src) (or use RawFSUtils.inSubtree semantics) with your own error message

Example fix

// before
fs.rename(new Path("/a/b"), new Path("/a/b/c")); // dest under src -> IOException

// after
fs.rename(new Path("/a/b"), new Path("/a/c")); // dest outside src subtree
Defensive patterns

Strategy: validation

Validate before calling

static boolean isUnder(Path src, Path dst) {
  // true when dst is a descendant of src
  for (Path p = dst.getParent(); p != null; p = p.getParent()) {
    if (p.equals(src)) return true;
  }
  return false;
}
if (isUnder(makeQualified(src), makeQualified(dst))) throw new IllegalArgumentException("dest under src");

Try / catch

try { fs.rename(src, dst); }
catch (IOException e) {
  if (e.getMessage() != null && e.getMessage().contains("prohibited to rename")) { /* fix paths */ }
  else throw e;
}

Prevention

When it happens

Trigger: rename('/a/b', '/a/b/c') or any rename where dest (after the 'dest is an existing dir' adjustment of appending src.getName()) is a strict descendant of src, e.g. renaming a directory into a subdirectory of itself.

Common situations: Shell-script style 'move into self' mistakes ported to the object store; job code computing destination paths from source paths and accidentally nesting them; archive routines that build dest as src + '/archive'.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/6f3674a787f6cef7. Report an issue: GitHub.