apache/hadoop · error · PathIsNotEmptyDirectoryException

{path}

Error message

{path}

What it means

For directory deletes, the code checks whether the directory prefix has any contents; delete(f, recursive=false) on a non-empty directory throws Hadoop's PathIsNotEmptyDirectoryException with the path string as the message. The bucket root is refused separately by rejectRootDirectoryDelete, and an empty directory marker is deleted as a single object.

Source

Thrown at hadoop-cloud-storage-project/hadoop-huaweicloud/src/main/java/org/apache/hadoop/fs/obs/OBSObjectBucketUtils.java:260

    String key = OBSCommonUtils.pathToKey(owner, f);

    if (status.isDirectory()) {
      LOG.debug("delete: Path is a directory: {} - recursive {}", f,
          recursive);

      key = OBSCommonUtils.maybeAddTrailingSlash(key);
      if (!key.endsWith("/")) {
        key = key + "/";
      }

      boolean isEmptyDir = OBSCommonUtils.isFolderEmpty(owner, key);
      if (key.equals("/")) {
        return OBSCommonUtils.rejectRootDirectoryDelete(
            owner.getBucket(), isEmptyDir, recursive);
      }

      if (!recursive && !isEmptyDir) {
        throw new PathIsNotEmptyDirectoryException(f.toString());
      }

      if (isEmptyDir) {
        LOG.debug(
            "delete: Deleting fake empty directory {} - recursive {}",
            f, recursive);
        OBSCommonUtils.deleteObject(owner, key);
      } else {
        LOG.debug(
            "delete: Deleting objects for directory prefix {} "
                + "- recursive {}",
            f, recursive);
        deleteNonEmptyDir(owner, recursive, key);
      }

    } else {
      LOG.debug("delete: Path is a file");
      OBSCommonUtils.deleteObject(owner, key);

View on GitHub (pinned to 2add963021)

Solutions

  1. Pass recursive=true when the whole tree should be removed: fs.delete(dir, true)
  2. List and delete children explicitly when only some entries should go
  3. On a suspected race, catch the exception, re-list, and retry once

Example fix

// before
fs.delete(dir, false);

// after
fs.delete(dir, true);
Defensive patterns

Strategy: validation

Validate before calling

if (fs.getFileStatus(dir).isDirectory()) {
  boolean empty = !fs.listStatus(dir).iterator().hasNext()
      && fs.listStatus(dir).length == 0;
  if (!empty) {
    // pass recursive=true, or delete children selectively
  }
}

Type guard

static boolean isEmptyDirectory(FileSystem fs, Path p) throws IOException {
  return fs.getFileStatus(p).isDirectory() && fs.listStatus(p).length == 0;
}

Try / catch

try {
  fs.delete(dir, false);
} catch (PathIsNotEmptyDirectoryException e) {
  // content appeared between check and delete: list again and decide,
  // or escalate to fs.delete(dir, true) if full removal is intended
}

Prevention

When it happens

Trigger: fs.delete(dir, false) when dir contains objects or subdirectory markers; cleanup code written for a POSIX filesystem where false was thought sufficient; dropping a partition directory without the recursive flag.

Common situations: Porting local-filesystem utilities to object storage where 'directory' means a prefix with keys; a race where another writer adds an object between the emptiness check and the delete call; Hive/Spark partition drop configured non-recursive.

Related errors


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