{"record":{"id":"88963d1e41c5b0c3","repo":"apache/hadoop","slug":"is-root-directory","errorCode":null,"errorMessage":"{} is root directory","messagePattern":"(.+?) is root directory","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-cloud-storage-project/hadoop-huaweicloud/src/main/java/org/apache/hadoop/fs/obs/OBSObjectBucketUtils.java","lineNumber":103,"sourceCode":"   * @throws RenameFailedException if some criteria for a state changing rename\n   *                               was not met. This means work didn't happen;\n   *                               it's not something which is reported upstream\n   *                               to the FileSystem APIs, for which the\n   *                               semantics of \"false\" are pretty vague.\n   * @throws FileNotFoundException there's no source file.\n   * @throws IOException           on IO failure.\n   * @throws ObsException          on failures inside the OBS SDK\n   */\n  static boolean renameBasedOnObject(final OBSFileSystem owner,\n      final Path src, final Path dst) throws RenameFailedException,\n      FileNotFoundException, IOException,\n      ObsException {\n    String srcKey = OBSCommonUtils.pathToKey(owner, src);\n    String dstKey = OBSCommonUtils.pathToKey(owner, dst);\n\n    if (srcKey.isEmpty()) {\n      LOG.error(\"rename: src [{}] is root directory\", src);\n      throw new IOException(src + \" is root directory\");\n    }\n\n    // get the source file status; this raises a FNFE if there is no source\n    // file.\n    FileStatus srcStatus = owner.getFileStatus(src);\n\n    FileStatus dstStatus;\n    try {\n      dstStatus = owner.getFileStatus(dst);\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 (dstStatus.isDirectory()) {\n        String newDstKey = OBSCommonUtils.maybeAddTrailingSlash(dstKey);\n        String filename = srcKey.substring(\n            OBSCommonUtils.pathToKey(owner, src.getParent()).length()\n                + 1);","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-cloud-storage-project/hadoop-huaweicloud/src/main/java/org/apache/hadoop/fs/obs/OBSObjectBucketUtils.java#L85-L121","documentation":"renameBasedOnObject converts the source Path to an object key; the bucket root converts to the empty key. An empty srcKey means the caller asked to rename the bucket itself, which object storage cannot express, so the code logs 'rename: src [...] is root directory' and throws IOException('<src> is root directory') before any status lookup.","triggerScenarios":"FileSystem.rename(new Path(\"/\"), dst) on an OBS object bucket; renaming obs://bucket/ directly; path arithmetic that strips the entire prefix; a loop on getParent() that terminates at root (Path.getParent() of the root returns the root itself) and then feeds it to rename.","commonSituations":"Compaction or migration jobs whose source directory is computed from configuration and defaults to the bucket root; cleanup utilities that walk upward to the top; staging-directory moves where the configured source is empty or '/'","solutions":["Reject or skip the operation when src.isRoot() (or when the key derived from it is empty)","Fix the path computation that collapses to the bucket root","Run jobs inside a dedicated prefix such as /user/ or /data/ instead of the bucket root"],"exampleFix":"// before\nfs.rename(new Path(\"/\"), new Path(\"/archive\"));\n\n// after\nPath src = new Path(\"/data\");\nif (!src.isRoot()) {\n  fs.rename(src, new Path(\"/archive/data\"));\n}","handlingStrategy":"validation","validationCode":"if (src.isRoot()) {\n  throw new IllegalArgumentException(\"Refusing to rename the bucket root: \" + src);\n}\n// safer for arbitrary paths:\nif (fs.getFileStatus(src).isDirectory() && src.isRoot()) {\n  throw new IllegalArgumentException(\"Source is the bucket root\");\n}","typeGuard":"static boolean isBucketRoot(Path p) {\n  return p.isRoot();\n}","tryCatchPattern":"try {\n  fs.rename(src, dst);\n} catch (IOException e) {\n  if (e.getMessage() != null && e.getMessage().endsWith(\"is root directory\")) {\n    // source resolved to the bucket root: fix the source path\n  } else {\n    throw e;\n  }\n}","preventionTips":["Guard isRoot() before any rename or delete loop","Treat an empty key derived from a path as invalid input","Unit-test path arithmetic with the root path as a boundary case","Run jobs inside dedicated prefixes, never against the bucket top level"],"tags":["hadoop","obs","rename","bucket-root","object-storage"],"backgroundTag":"rename-root-directory","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}