apache/hadoop · error · IOException

Source path and dest path refer the same file or directory

Error message

Source path and dest path refer the same file or directory

What it means

rename(src, dst) throws IOException('Source path and dest path refer the same file or directory') when src.equals(dst). Unlike some FileSystem implementations that return true or false for a self-rename, CosN treats renaming a path onto itself as a caller error and fails fast. The check runs after the source-exists check and before the ancestor checks.

Source

Thrown at hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNFileSystem.java:620

  @Override
  public boolean rename(Path src, Path dst) throws IOException {
    LOG.debug("Rename source path: [{}] to dest path: [{}].", src, dst);

    // Renaming the root directory is not allowed
    if (src.isRoot()) {
      LOG.debug("Cannot rename the root directory of a filesystem.");
      return false;
    }

    // check the source path whether exists or not
    FileStatus srcFileStatus = this.getFileStatus(src);

    // Source path and destination path are not allowed to be the same
    if (src.equals(dst)) {
      LOG.debug("Source path and dest path refer to "
          + "the same file or directory: [{}].", dst);
      throw new IOException("Source path and dest path refer "
          + "the same file or directory");
    }

    // It is not allowed to rename a parent directory to its subdirectory
    Path dstParentPath;
    for (dstParentPath = dst.getParent();
         null != dstParentPath && !src.equals(dstParentPath);
         dstParentPath = dstParentPath.getParent()) {
      // Recursively find the common parent path of the source and
      // destination paths.
      LOG.debug("Recursively find the common parent directory of the source "
              + "and destination paths. The currently found parent path: {}",
          dstParentPath);
    }

    if (null != dstParentPath) {
      LOG.debug("It is not allowed to rename a parent directory:[{}] "
          + "to its subdirectory:[{}].", src, dst);

View on GitHub (pinned to 2add963021)

Solutions

  1. Guard before calling: if src.equals(dst), skip and treat as success.
  2. Qualify both paths with fs.makeQualified(src/dst) before comparing or renaming.
  3. Validate user-supplied move parameters and fail early with a clear message.

Example fix

// before
fs.rename(src, dst); // IOException when src.equals(dst)

// after
if (!fs.makeQualified(src).equals(fs.makeQualified(dst))) {
  fs.rename(src, dst);
}
Defensive patterns

Strategy: validation

Validate before calling

Path s = fs.makeQualified(src);
Path d = fs.makeQualified(dst);
if (s.equals(d)) {
  return true; // self-move is a no-op success
}
return fs.rename(s, d);

Try / catch

try {
  fs.rename(src, dst);
} catch (IOException e) {
  if (src.equals(dst) || e.getMessage().contains('the same file or directory')) {
    return true; // treat as no-op
  }
  throw e;
}

Prevention

When it happens

Trigger: fs.rename(p, p); a computed destination collapses onto the source after Path normalization — e.g. rename('/a/b', '/a/b/') where the trailing slash normalizes away, or unqualified vs qualified forms of the same path comparing equal.

Common situations: Move logic built from user input where src and dst coincide; mixing 'cosn://bucket/x' and relative '/x' forms that resolve to the same key; config-driven rename where source and destination variables point at the same location.

Related errors


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