prestodb/presto · error · IOException

Directory is not empty

Error message

Directory  is not empty

What it means

delete(path, recursive=false) on a path that resolves to a directory (prefix) throws IOException because non-recursive delete cannot remove a non-empty S3 prefix. S3 has no directories; the connector emulates them and refuses to delete a prefix that still has children without recursion.

Source

Thrown at presto-hive/src/main/java/com/facebook/presto/hive/s3/PrestoS3FileSystem.java:522

        return true;
    }

    @Override
    public boolean delete(Path path, boolean recursive)
            throws IOException
    {
        try {
            if (!directory(path)) {
                return deleteObject(keyFromPath(path));
            }
        }
        catch (FileNotFoundException e) {
            return false;
        }

        if (!recursive) {
            throw new IOException("Directory " + path + " is not empty");
        }

        for (FileStatus file : listStatus(path)) {
            delete(file.getPath(), true);
        }
        deleteObject(keyFromPath(path) + DIRECTORY_SUFFIX);

        return true;
    }

    private boolean directory(Path path)
            throws IOException
    {
        return getFileStatus(path).isDirectory();
    }

    private boolean deleteObject(String key)
    {

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Call delete(path, true) to recursively remove the prefix's contents.
  2. Delete the individual files first, then the directory marker.
  3. If the directory should be empty, list and confirm what remains (likely hidden objects with DIRECTORY_SUFFIX).
  4. For rename, ensure the source location is emptied or use recursive deletion of children first.

Example fix

// before
fs.delete(new Path("s3://bucket/table/partition=1"), false);
// after
fs.delete(new Path("s3://bucket/table/partition=1"), true); // recursive
Defensive patterns

Strategy: validation

Validate before calling

FileStatus st = fs.getFileStatus(path);
if (st.isDirectory() && !recursive && fs.listStatus(path).length > 0) {
    throw new IllegalStateException("refusing non-recursive delete of non-empty dir: " + path);
}

Type guard

null

Try / catch

try {
    fs.delete(path, recursive);
} catch (IOException e) {
    if (e.getMessage().contains("is not empty")) {
        fs.delete(path, true); // or fail loudly per policy
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling fs.delete(dirPath, false) where the prefix contains objects; rename() internally calls delete on a non-empty source without recursion; a caller calling delete(path, false) on the only child's parent accidentally.

Common situations: Cleaning up table partitions with false flag; HDFS-style code assuming empty-dir deletion; rename of directories that still contain files.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/e4f398b9a8025dfa. Report an issue: GitHub.