{"record":{"id":"95cf297ff5fa9c72","repo":"apache/hadoop","slug":"dest-is-root-directory","errorCode":null,"errorMessage":"dest is root directory","messagePattern":"dest is root directory","errorType":"exception","errorClass":"RenameFailedException","httpStatus":null,"severity":"warning","filePath":"hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AFileSystem.java","lineNumber":2438,"sourceCode":"   * @throws RenameFailedException if some criteria for a state changing\n   * rename was not met. This means work didn't happen; it's not something\n   * which is reported upstream to the FileSystem APIs, for which the semantics\n   * of \"false\" are pretty vague.\n   * @throws FileNotFoundException there's no source file.\n   * @throws IOException on IO failure.\n   */\n  @Retries.RetryTranslated\n  private Pair<S3AFileStatus, S3AFileStatus> initiateRename(\n      final Path src,\n      final Path dst) throws IOException {\n    String srcKey = pathToKey(src);\n    String dstKey = pathToKey(dst);\n\n    if (srcKey.isEmpty()) {\n      throw new RenameFailedException(src, dst, \"source is root directory\");\n    }\n    if (dstKey.isEmpty()) {\n      throw new RenameFailedException(src, dst, \"dest is root directory\");\n    }\n\n    // get the source file status; this raises a FNFE if there is no source\n    // file.\n    S3AFileStatus srcStatus = innerGetFileStatus(src, true,\n        StatusProbeEnum.ALL);\n\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);","sourceCodeStart":2420,"sourceCodeEnd":2456,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AFileSystem.java#L2420-L2456","documentation":"initiateRename() maps dst to an S3 key; an empty dstKey means the destination is the bucket root. Renaming anything onto s3a://bucket/ is meaningless, so RenameFailedException 'dest is root directory' is thrown; rename() catches it, logs INFO, and returns false (default exit code).","triggerScenarios":"rename(src, new Path(\"/\")) or any dst qualifying to the bucket root; 'move file to top level' logic that drops the filename when building the destination.","commonSituations":"Destination built as dst.getParent() of a top-level path; normalization dropping the last path element; code assuming rename-to-directory semantics where the directory is the root itself.","solutions":["Build an explicit destination under root: new Path(new Path(\"/\"), src.getName())","Fix destination computation so the last path element is preserved","Check dst.isRoot() before calling rename"],"exampleFix":"// before\nPath dst = new Path(\"/\");\nfs.rename(src, dst);\n\n// after: keep the file name at bucket top level\nPath dst = new Path(new Path(\"/\"), src.getName());\nfs.rename(src, dst);","handlingStrategy":"validation","validationCode":"if (dst.isRoot()) {\n  dst = new Path(new Path(\"/\"), src.getName());\n}\nfs.rename(src, dst);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always build destinations as new Path(dir, src.getName())","Assert the destination has a non-empty last element in rename wrappers","Remember the failure mode is rename()==false with an INFO log, not an exception"],"tags":["s3a","rename","root","invalid-argument"],"backgroundTag":"rename-invalid-path","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}