apache/hadoop · error · PathIOException

Cannot delete root path

Error message

Cannot delete root path

What it means

Thrown by AliyunOSSFileSystem.rejectRootDirectoryDelete(): a delete targeted the bucket root ('/'), the bucket is not empty, and recursive=false. Deleting an entire bucket's contents implicitly is destructive, so the connector raises PathIOException(bucket, "Cannot delete root path") instead. (An empty root returns true; recursive=true is allowed to proceed.)

Source

Thrown at hadoop-tools/hadoop-aliyun/src/main/java/org/apache/hadoop/fs/aliyun/oss/AliyunOSSFileSystem.java:251

   * attempt to continue with the delete operation: deleting root
   * directories is never allowed. This method simply implements
   * the policy of when to return an exit code versus raise an exception.
   * @param isEmptyDir empty directory or not
   * @param recursive recursive flag from command
   * @return a return code for the operation
   * @throws PathIOException if the operation was explicitly rejected.
   */
  private boolean rejectRootDirectoryDelete(boolean isEmptyDir,
      boolean recursive) throws IOException {
    LOG.info("oss delete the {} root directory of {}", bucket, recursive);
    if (isEmptyDir) {
      return true;
    }
    if (recursive) {
      return false;
    } else {
      // reject
      throw new PathIOException(bucket, "Cannot delete root path");
    }
  }

  private void createFakeDirectoryIfNecessary(Path f) throws IOException {
    String key = pathToKey(f);
    if (StringUtils.isNotEmpty(key) && !exists(f)) {
      LOG.debug("Creating new fake directory at {}", f);
      mkdir(pathToKey(f.getParent()));
    }
  }

  @Override
  public FileStatus getFileStatus(Path path) throws IOException {
    Path qualifiedPath = path.makeQualified(uri, workingDir);
    String key = pathToKey(qualifiedPath);

    // Root always exists
    if (key.length() == 0) {

View on GitHub (pinned to 2add963021)

Solutions

  1. Target the specific subdirectory to delete (oss://bucket/prefix) instead of the bucket root
  2. If wiping the bucket is truly intended, pass recursive=true with extreme care, or delete via the OSS console/API
  3. Constrain cleanup code to never construct a delete on the root path; assert path depth before calling delete

Example fix

// before
fs.delete(new Path("oss://my-bucket/"), false); // Cannot delete root path

// after
fs.delete(new Path("oss://my-bucket/dataset/"), true);
Defensive patterns

Strategy: validation

Validate before calling

Path toDelete = path;
if (toDelete.isRoot() || toDelete.depth() <= 1) {
  throw new IOException("Refusing to delete bucket root: " + toDelete);
}
fs.delete(toDelete, true);

Try / catch

catch (PathIOException e) { /* root-delete guard tripped: never widen; fix the caller's path construction */ throw e; }

Prevention

When it happens

Trigger: Calling fs.delete(new Path("oss://bucket/"), false) — directly or via 'hadoop fs -rm oss://bucket' — when any object exists in the bucket; generic cleanup code that walks to the filesystem root and deletes what it sees.

Common situations: Recursive cleanup routines that reach the root after deleting children; tools that call delete on an empty-string path; guarding against accidental bucket wipes in production data lakes.

Related errors


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