apache/hadoop · error · IOException

Directory: {file} 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.

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)

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.