apache/hadoop · error · IOException

Cannot remove directory {f}: It is not empty!

Error message

Cannot remove directory {f}: It is not empty!

What it means

Thrown by AliyunOSSFileSystem.delete(): the target is a directory, recursive=false, and listStatus() on it returned one or more entries. Object stores cannot atomically delete a 'directory' with children in non-recursive mode, so the connector refuses with IOException("Cannot remove directory " + f + ": It is not empty!") to emulate POSIX rm semantics.

Source

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

  private boolean innerDelete(FileStatus status, boolean recursive)
      throws IOException {
    Path f = status.getPath();
    String p = f.toUri().getPath();
    FileStatus[] statuses;
    // indicating root directory "/".
    if (p.equals("/")) {
      statuses = listStatus(status.getPath());
      boolean isEmptyDir = statuses.length <= 0;
      return rejectRootDirectoryDelete(isEmptyDir, recursive);
    }

    String key = pathToKey(f);
    if (status.isDirectory()) {
      if (!recursive) {
        // Check whether it is an empty directory or not
        statuses = listStatus(status.getPath());
        if (statuses.length > 0) {
          throw new IOException("Cannot remove directory " + f +
              ": It is not empty!");
        } else {
          // Delete empty directory without '-r'
          key = AliyunOSSUtils.maybeAddTrailingSlash(key);
          store.deleteObject(key);
        }
      } else {
        store.deleteDirs(key);
      }
    } else {
      store.deleteObject(key);
    }

    createFakeDirectoryIfNecessary(f);
    return true;
  }

  /**

View on GitHub (pinned to 2add963021)

Solutions

  1. Pass recursive=true when the intent is to delete the whole subtree: fs.delete(path, true)
  2. If it must be empty, list the children first and delete/move them, then delete the directory key
  3. Check for non-obvious child keys (including zero-byte directory markers) with listStatus before assuming emptiness

Example fix

// before
fs.delete(dirPath, /*recursive*/ false);

// after
fs.delete(dirPath, /*recursive*/ true);
Defensive patterns

Strategy: validation

Validate before calling

FileStatus st = fs.getFileStatus(dir);
if (st.isDirectory() && fs.listStatus(dir).length > 0) {
  boolean recursive = /* user intent */ true;
  if (!recursive) throw new IOException("Directory not empty: " + dir);
}
fs.delete(dir, recursive);

Try / catch

catch (IOException e) { if (e.getMessage().startsWith("Cannot remove directory")) { /* escalate to delete(path, true) or delete children manually */ } throw e; }

Prevention

When it happens

Trigger: Calling fs.delete(path, false) on an OSS prefix that contains objects or child prefixes; shell 'hadoop fs -rm oss://bucket/dir' (non-recursive default) where dir has children.

Common situations: Cleanup scripts ported from HDFS that used rm without -r on directories; assuming an empty directory exists when OSS still holds a zero-byte marker or hidden child keys (e.g., _SUCCESS, .crc files, or 'fake directory' markers from other tools).

Related errors


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