{"record":{"id":"1784eda172ba67bc","repo":"apache/hadoop","slug":"failed-to-rename-src-to-dst-source-is-a-direc","errorCode":null,"errorMessage":"Failed to rename <src> to <dst>; source is a directory and dest is a file","messagePattern":"Failed to rename <src> to <dst>; source is a directory and dest is a file","errorType":"exception","errorClass":"FileAlreadyExistsException","httpStatus":null,"severity":"error","filePath":"hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AFileSystem.java","lineNumber":2463,"sourceCode":"\n    if (srcKey.equals(dstKey)) {\n      LOG.debug(\"rename: src and dest refer to the same file or directory: {}\",\n          dst);\n      throw new RenameFailedException(src, dst,\n          \"source and dest refer to the same file or directory\")\n          .withExitCode(srcStatus.isFile());\n    }\n\n    S3AFileStatus dstStatus = null;\n    try {\n      dstStatus = innerGetFileStatus(dst, true, StatusProbeEnum.ALL);\n      // if there is no destination entry, an exception is raised.\n      // hence this code sequence can assume that there is something\n      // at the end of the path; the only detail being what it is and\n      // whether or not it can be the destination of the rename.\n      if (srcStatus.isDirectory()) {\n        if (dstStatus.isFile()) {\n          throw new FileAlreadyExistsException(\n              \"Failed to rename \" + src + \" to \" + dst\n               +\"; source is a directory and dest is a file\");\n        } else if (dstStatus.isEmptyDirectory() != Tristate.TRUE) {\n          throw new RenameFailedException(src, dst,\n              \"Destination is a non-empty directory\")\n              .withExitCode(false);\n        }\n        // at this point the destination is an empty directory\n      } else {\n        // source is a file. The destination must be a directory,\n        // empty or not\n        if (dstStatus.isFile()) {\n          throw new FileAlreadyExistsException(\n              \"Failed to rename \" + src + \" to \" + dst\n                  + \"; destination file exists\");\n        }\n      }\n","sourceCodeStart":2445,"sourceCodeEnd":2481,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AFileSystem.java#L2445-L2481","documentation":"In initiateRename(), after both statuses resolved successfully: srcStatus.isDirectory() and dstStatus.isFile(). A directory tree cannot be moved onto a single object, so FileAlreadyExistsException 'Failed to rename <src> to <dst>; source is a directory and dest is a file' is thrown. Unlike RenameFailedException this is not caught by rename(), so it propagates to the caller as an IOException.","triggerScenarios":"rename(dir, existingFile); destination previously written as a file while the source path later became a directory; concurrent jobs writing a file where another is renaming a directory.","commonSituations":"Schema evolution where yesterday's file path is today's partition directory; pipeline reruns with restructured output; recovery flows renaming directories over stale marker files.","solutions":["Delete or move the destination file, then retry the rename","Choose a destination that does not exist or is an empty directory","Pre-check fs.getFileStatus(dst) before launching expensive work and fail early with context"],"exampleFix":"// before\nfs.rename(srcDir, dst);\n\n// after: clear a stale destination file first\nif (fs.exists(dst) && fs.getFileStatus(dst).isFile()) {\n  fs.delete(dst, false);\n}\nfs.rename(srcDir, dst);","handlingStrategy":"validation","validationCode":"if (fs.exists(dst) && fs.getFileStatus(dst).isFile()) {\n  throw new IOException(\"destination exists as a file: \" + dst);\n}\nfs.rename(src, dst);","typeGuard":null,"tryCatchPattern":"Catch FileAlreadyExistsException from rename(): it escapes rename() (unlike RenameFailedException). Decide replace-vs-abort based on your publishing contract before deleting the destination file.","preventionTips":["Pre-check destination status before large renames","Keep output layouts stable between runs to avoid dir-vs-file collisions","Delete stale destinations in idempotent job setup"],"tags":["s3a","rename","file-already-exists","type-mismatch"],"backgroundTag":"file-already-exists","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}