{"record":{"id":"d02db079e8b186d8","repo":"apache/hadoop","slug":"cannot-delete-root-path","errorCode":null,"errorMessage":"Cannot delete root path","messagePattern":"Cannot delete root path","errorType":"exception","errorClass":"PathIOException","httpStatus":null,"severity":"error","filePath":"hadoop-cloud-storage-project/hadoop-huaweicloud/src/main/java/org/apache/hadoop/fs/obs/OBSCommonUtils.java","lineNumber":696,"sourceCode":"   * @param bucket     bucket name\n   * @param isEmptyDir flag indicating if the directory is empty\n   * @param recursive  recursive flag from command\n   * @return a return code for the operation\n   * @throws PathIOException if the operation was explicitly rejected.\n   */\n  static boolean rejectRootDirectoryDelete(final String bucket,\n      final boolean isEmptyDir,\n      final boolean recursive)\n      throws IOException {\n    LOG.info(\"obs delete the {} root directory of {}\", bucket, recursive);\n    if (isEmptyDir) {\n      return true;\n    }\n    if (recursive) {\n      return false;\n    } else {\n      // reject\n      throw new PathIOException(bucket, \"Cannot delete root path\");\n    }\n  }\n\n  /**\n   * Make the given path and all non-existent parents into directories.\n   *\n   * @param owner the owner OBSFileSystem instance\n   * @param path  path to create\n   * @return true if a directory was created\n   * @throws FileAlreadyExistsException there is a file at the path specified\n   * @throws IOException                other IO problems\n   * @throws ObsException               on failures inside the OBS SDK\n   */\n  static boolean innerMkdirs(final OBSFileSystem owner, final Path path)\n      throws IOException, FileAlreadyExistsException, ObsException {\n    LOG.debug(\"Making directory: {}\", path);\n    FileStatus fileStatus;\n    try {","sourceCodeStart":678,"sourceCodeEnd":714,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-cloud-storage-project/hadoop-huaweicloud/src/main/java/org/apache/hadoop/fs/obs/OBSCommonUtils.java#L678-L714","documentation":"OBSCommonUtils.rejectRootDirectoryDelete(bucket, isEmptyDir, recursive) implements delete(obs://bucket/, ...) policy: if the root directory is empty it returns true (nothing to do); if recursive=true it returns false (proceed to recursive delete); otherwise it throws PathIOException(bucket, 'Cannot delete root path'). So this error means: non-recursive delete() was invoked on a NON-EMPTY bucket root — the connector refuses a shallow delete that would need to remove uncounted children.","triggerScenarios":"fs.delete(new Path(\"obs://bucket/\"), false) (or new Path(\"obs://bucket\")) when the bucket contains any objects or directory markers; code paths that call delete(path, false) on a path that resolves to root; cleanup routines that mirror HDFS semantics where deleting a non-empty dir non-recursively throws DirectoryNotEmptyException.","commonSituations":"Automated cleanup scripts deleting configured 'base dir' set to the bucket root; tools ported from HDFS that call delete(dir,false) expecting ENOENT-style failure; mistyped path config dropping the subdirectory component so the effective path is root.","solutions":["If clearing the bucket is intended: call fs.delete(root, true) — recursive=true is allowed and empties the bucket (still does not delete the bucket itself).","If not intended: fix the path so it points at the intended subdirectory, not the bucket root; assert path.isRoot() is false before delete.","Catch PathIOException around cleanup code and treat 'Cannot delete root path' as a configuration bug alert rather than retrying.","For HDFS-compatible behavior, pre-check listStatus(root).length or use a marker subdirectory as the logical root of your data."],"exampleFix":"// before\nfs.delete(new Path(\"obs://mybucket/\"), false); // non-empty root -> PathIOException\n\n// after\nPath root = new Path(\"obs://mybucket/\");\nif (shouldWipeBucket) {\n  fs.delete(root, true);      // recursive clear allowed\n} else {\n  fs.delete(new Path(root, \"staging/\"), true); // target a subdir, never root\n}","handlingStrategy":"validation","validationCode":"static void requireNonRootDelete(OBSFileSystem fs, Path p, boolean recursive) throws IOException {\n  if (p.isRoot() || \"/\".equals(p.toUri().getPath())) {\n    if (!recursive) throw new IllegalArgumentException(\"use recursive=true to clear bucket root\");\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  fs.delete(rootPath, false);\n} catch (PathIOException e) {\n  if (\"Cannot delete root path\".equals(e.getMessage())) {\n    throw new ConfigException(\"Cleanup targeted bucket root; fix base-dir config\", e);\n  }\n  throw e;\n}","preventionTips":["Always pass explicit recursive=true/false; never infer from a variable you don't control.","Point cleanup configs at a subdirectory, never the bare bucket URI.","Unit-test cleanup routines against empty buckets to catch root-targeting early."],"tags":["obs","huaweicloud","delete","root-guard","path-io-exception"],"backgroundTag":"delete-root-of-bucket","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}