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
- Call delete(path, true) to recursively remove the prefix's contents.
- Delete the individual files first, then the directory marker.
- If the directory should be empty, list and confirm what remains (likely hidden objects with DIRECTORY_SUFFIX).
- 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
- Default to recursive=true for directory-style prefixes.
- List contents before deleting to confirm scope.
- Never assume S3 prefixes behave like empty HDFS directories.
- Delete child objects before removing the directory marker.
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.