apache/hadoop · error · FileAlreadyExistsException

The source {src} and destination {dst} are the same

Error message

The source {src} and destination {dst} are the same

What it means

The default (non-atomic) rename-with-overwrite in AbstractFileSystem first stats both ends; when the destination exists and dst.equals(src) (Path equality is URI equality), it throws FileAlreadyExistsException — renaming an entry onto itself is refused as a no-op. A sibling branch also rejects renaming a symlink onto its own target.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/AbstractFileSystem.java:863

   * @throws UnresolvedLinkException unresolved link exception.
   * @throws IOException raised on errors performing I/O.
   */
  public void renameInternal(final Path src, final Path dst,
      boolean overwrite) throws AccessControlException,
      FileAlreadyExistsException, FileNotFoundException,
      ParentNotDirectoryException, UnresolvedLinkException, IOException {
    // Default implementation deals with overwrite in a non-atomic way
    final FileStatus srcStatus = getFileLinkStatus(src);

    FileStatus dstStatus;
    try {
      dstStatus = getFileLinkStatus(dst);
    } catch (IOException e) {
      dstStatus = null;
    }
    if (dstStatus != null) {
      if (dst.equals(src)) {
        throw new FileAlreadyExistsException(
            "The source "+src+" and destination "+dst+" are the same");
      }
      if (srcStatus.isSymlink() && dst.equals(srcStatus.getSymlink())) {
        throw new FileAlreadyExistsException(
            "Cannot rename symlink "+src+" to its target "+dst);
      }
      // It's OK to rename a file to a symlink and vice versa
      if (srcStatus.isDirectory() != dstStatus.isDirectory()) {
        throw new IOException("Source " + src + " and destination " + dst
            + " must both be directories");
      }
      if (!overwrite) {
        throw new FileAlreadyExistsException("Rename destination " + dst
            + " already exists.");
      }
      // Delete the destination that is a file or an empty directory
      if (dstStatus.isDirectory()) {
        RemoteIterator<FileStatus> list = listStatusIterator(dst);

View on GitHub (pinned to 2add963021)

Solutions

  1. Skip the operation when the fully-qualified paths are equal: if (fc.makeQualified(src).equals(fc.makeQualified(dst))) return;
  2. Fix the destination computation so it genuinely differs (distinct name, subdirectory, or timestamp suffix)
  3. Validate src != dst at the API boundary of your move/rename helpers and report it as a no-op, not an error

Example fix

// before
fc.rename(src, dst, Rename.OVERWRITE); // src and dst resolve to the same path

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

Strategy: validation

Validate before calling

Path qs = fc.makeQualified(src), qd = fc.makeQualified(dst);
if (qs.equals(qd)) {
  return; // moving onto itself: treat as no-op
}
fc.rename(src, dst, Rename.OVERWRITE);

Try / catch

catch (FileAlreadyExistsException e) { if (srcQualified.equals(dstQualified)) { /* no-op move: skip */ } else throw e; }

Prevention

When it happens

Trigger: rename(a, a) with a existing; loops that compute a destination which degenerates to the source path ("move to same location"); dst produced by makeQualified/makeQualified-equivalent that ends up with the identical URI as src.

Common situations: Archive/compaction jobs whose filter selects nothing so the computed destination equals the input; output directory configured equal to input directory; distcp-style tooling where src and dst resolve to the same qualified path; renames inside loops with per-row destinations.

Related errors


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