apache/hadoop · error · IOException

Directory: is not empty.

Error message

Directory: {file} is not empty.

What it means

delete(path, recursive=false) lists the directory first; if it contains any entries and recursion is off, deletion is refused with this IOException rather than silently dropping content. Only delete(path, true) walks and removes children.

Solutions

  1. Call fs.delete(path, true) when recursive deletion is intended
  2. If only empty directories should be removed, check fs.listStatus(dir).length == 0 first and skip otherwise
  3. List the directory to see what entries exist — dotfiles count as entries

Example fix

// before
fs.delete(dir, false); // IOException: Directory: ... is not empty.

// after
if (fs.getFileStatus(dir).isDirectory() && fs.listStatus(dir).length > 0) {
  boolean ok = fs.delete(dir, true); // recursive delete intended
} else {
  fs.delete(dir, false);
}
Defensive patterns

Strategy: validation

Validate before calling

if (fs.getFileStatus(dir).isDirectory() && fs.listStatus(dir).length > 0) {
  boolean removed = fs.delete(dir, true); // explicit recursive decision
} else {
  fs.delete(dir, false);
}

Type guard

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

Try / catch

try {
  fs.delete(dir, false);
} catch (IOException e) {
  if (e.getMessage() != null && e.getMessage().contains("not empty")) {
    fs.delete(dir, true); // only if recursive delete is acceptable
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: fs.delete(dir, false) on a non-empty FTP directory; cleanup code assuming the directory is empty; hidden entries (dotfiles, subdirectories) making a directory look empty to the user.

Common situations: Job cleanup expecting an empty output dir; FTP servers that list hidden files; shared upload directories that accumulate entries between runs.

Related errors


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

Appendix: source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ftp/FTPFileSystem.java:432

   * the overhead of opening/closing a TCP connection.
   */
  private boolean delete(FTPClient client, Path file, boolean recursive)
      throws IOException {
    Path workDir = new Path(client.printWorkingDirectory());
    Path absolute = makeAbsolute(workDir, file);
    String pathName = absolute.toUri().getPath();
    try {
      FileStatus fileStat = getFileStatus(client, absolute);
      if (fileStat.isFile()) {
        return client.deleteFile(pathName);
      }
    } catch (FileNotFoundException e) {
      //the file is not there
      return false;
    }
    FileStatus[] dirEntries = listStatus(client, absolute);
    if (dirEntries != null && dirEntries.length > 0 && !(recursive)) {
      throw new IOException("Directory: " + file + " is not empty.");
    }
    for (FileStatus dirEntry : dirEntries) {
      delete(client, new Path(absolute, dirEntry.getPath()), recursive);
    }
    return client.removeDirectory(pathName);
  }

  @VisibleForTesting
  FsAction getFsAction(int accessGroup, FTPFile ftpFile) {
    FsAction action = FsAction.NONE;
    if (ftpFile.hasPermission(accessGroup, FTPFile.READ_PERMISSION)) {
      action = action.or(FsAction.READ);
    }
    if (ftpFile.hasPermission(accessGroup, FTPFile.WRITE_PERMISSION)) {
      action = action.or(FsAction.WRITE);
    }
    if (ftpFile.hasPermission(accessGroup, FTPFile.EXECUTE_PERMISSION)) {
      action = action.or(FsAction.EXECUTE);

View on GitHub (pinned to 2add963021)