apache/hadoop · info · RenameFailedException

source and dest refer to the same file or directory

Error message

source and dest refer to the same file or directory

What it means

In initiateRename(), srcKey.equals(dstKey) means source and destination resolve to the same S3 key, so the rename is a no-op. The code throws RenameFailedException 'source and dest refer to the same file or directory' with exit code srcStatus.isFile(): rename() catches it and returns that code - true when the source is a file (POSIX rename onto itself succeeds) and false when it is a directory. It is logged at INFO, never raised to the caller.

Source

Thrown at hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AFileSystem.java:2449

    String srcKey = pathToKey(src);
    String dstKey = pathToKey(dst);

    if (srcKey.isEmpty()) {
      throw new RenameFailedException(src, dst, "source is root directory");
    }
    if (dstKey.isEmpty()) {
      throw new RenameFailedException(src, dst, "dest is root directory");
    }

    // get the source file status; this raises a FNFE if there is no source
    // file.
    S3AFileStatus srcStatus = innerGetFileStatus(src, true,
        StatusProbeEnum.ALL);

    if (srcKey.equals(dstKey)) {
      LOG.debug("rename: src and dest refer to the same file or directory: {}",
          dst);
      throw new RenameFailedException(src, dst,
          "source and dest refer to the same file or directory")
          .withExitCode(srcStatus.isFile());
    }

    S3AFileStatus dstStatus = null;
    try {
      dstStatus = innerGetFileStatus(dst, true, StatusProbeEnum.ALL);
      // if there is no destination entry, an exception is raised.
      // hence this code sequence can assume that there is something
      // at the end of the path; the only detail being what it is and
      // whether or not it can be the destination of the rename.
      if (srcStatus.isDirectory()) {
        if (dstStatus.isFile()) {
          throw new FileAlreadyExistsException(
              "Failed to rename " + src + " to " + dst
               +"; source is a directory and dest is a file");
        } else if (dstStatus.isEmptyDirectory() != Tristate.TRUE) {
          throw new RenameFailedException(src, dst,

View on GitHub (pinned to 2add963021)

Solutions

  1. Treat rename(p, p) as success for files - the exit code already does; for directories skip the call
  2. Qualify both paths (src.makeQualified(fs)) and compare before renaming to avoid the no-op branch
  3. Log src/dst keys when debugging surprising rename results

Example fix

// before: may issue a self-rename on retry
fs.rename(src, dst);

// after: short-circuit identical destinations
if (src.makeQualified(fs).equals(dst.makeQualified(fs))) {
  return true;
}
return fs.rename(src, dst);
Defensive patterns

Strategy: validation

Validate before calling

// Skip self-renames before invoking the FS
if (src.makeQualified(fs).equals(dst.makeQualified(fs))) {
  return true; // already at destination
}
return fs.rename(src, dst);

Prevention

When it happens

Trigger: rename(src, src); src and dst strings that qualify to the same key (trailing slash, duplicated slashes, different URI encodings); retry logic re-invoking an already-completed rename.

Common situations: Idempotent retry wrappers re-running finished moves; two code paths normalizing the same path differently; case-sensitivity assumptions ported from other filesystems.

Related errors


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