apache/hadoop · error · PathIsNotEmptyDirectoryException

{path}

Error message

{path}

What it means

In the POSIX delete path, a directory is checked for contents with isFolderEmpty; delete(f, recursive=false) on a non-empty directory throws PathIsNotEmptyDirectoryException with the path string as the message. The bucket root (empty key) is refused separately, and an empty folder is deleted as a single object.

Source

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

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

    if (!status.isDirectory()) {
      LOG.debug("delete: Path is a file");
      trashObjectIfNeed(owner, key);
    } else {
      LOG.debug("delete: Path is a directory: {} - recursive {}", f,
          recursive);
      key = OBSCommonUtils.maybeAddTrailingSlash(key);
      boolean isEmptyDir = OBSCommonUtils.isFolderEmpty(owner, key);
      if (key.equals("")) {
        return OBSCommonUtils.rejectRootDirectoryDelete(
            owner.getBucket(), isEmptyDir, recursive);
      }
      if (!recursive && !isEmptyDir) {
        LOG.warn("delete: Path is not empty: {} - recursive {}", f,
            recursive);
        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 {} to "
                + "delete - recursive {}", f, recursive);
        trashFolderIfNeed(owner, key, f);
      }
    }

    long endTime = System.currentTimeMillis();
    LOG.debug("delete Path:{} thread:{}, timeUsedInMilliSec:{}", f,
        threadId, endTime - startTime);
    return true;

View on GitHub (pinned to 2add963021)

Solutions

  1. Pass recursive=true when the whole tree must go: fs.delete(dir, true)
  2. List and selectively delete children when only part of the content should be removed
  3. Re-check directory contents on failure when a concurrent-writer race is plausible

Example fix

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

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

Strategy: validation

Validate before calling

if (fs.getFileStatus(dir).isDirectory() && fs.listStatus(dir).length > 0
    && !recursive) {
  throw new PathIsNotEmptyDirectoryException(dir.toString());
}

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 arrived concurrently: re-list and choose delete(dir, true) or skip
}

Prevention

When it happens

Trigger: fs.delete(dir, false) while dir contains objects or subfolders; cleanup routines that assumed non-recursive delete on object storage removes everything; partition drops without the recursive flag.

Common situations: Code ported from HDFS or local filesystems; concurrent writers adding content between the emptiness check and the delete; scheduled cleanup jobs configured non-recursive by default.

Related errors


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