{"record":{"id":"e4f398b9a8025dfa","repo":"prestodb/presto","slug":"directory-is-not-empty","errorCode":null,"errorMessage":"Directory  is not empty","messagePattern":"Directory  is not empty","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"presto-hive/src/main/java/com/facebook/presto/hive/s3/PrestoS3FileSystem.java","lineNumber":522,"sourceCode":"\n        return true;\n    }\n\n    @Override\n    public boolean delete(Path path, boolean recursive)\n            throws IOException\n    {\n        try {\n            if (!directory(path)) {\n                return deleteObject(keyFromPath(path));\n            }\n        }\n        catch (FileNotFoundException e) {\n            return false;\n        }\n\n        if (!recursive) {\n            throw new IOException(\"Directory \" + path + \" is not empty\");\n        }\n\n        for (FileStatus file : listStatus(path)) {\n            delete(file.getPath(), true);\n        }\n        deleteObject(keyFromPath(path) + DIRECTORY_SUFFIX);\n\n        return true;\n    }\n\n    private boolean directory(Path path)\n            throws IOException\n    {\n        return getFileStatus(path).isDirectory();\n    }\n\n    private boolean deleteObject(String key)\n    {","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-hive/src/main/java/com/facebook/presto/hive/s3/PrestoS3FileSystem.java#L504-L540","documentation":"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.","triggerScenarios":"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.","commonSituations":"Cleaning up table partitions with false flag; HDFS-style code assuming empty-dir deletion; rename of directories that still contain files.","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."],"exampleFix":"// before\nfs.delete(new Path(\"s3://bucket/table/partition=1\"), false);\n// after\nfs.delete(new Path(\"s3://bucket/table/partition=1\"), true); // recursive","handlingStrategy":"validation","validationCode":"FileStatus st = fs.getFileStatus(path);\nif (st.isDirectory() && !recursive && fs.listStatus(path).length > 0) {\n    throw new IllegalStateException(\"refusing non-recursive delete of non-empty dir: \" + path);\n}","typeGuard":"null","tryCatchPattern":"try {\n    fs.delete(path, recursive);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"is not empty\")) {\n        fs.delete(path, true); // or fail loudly per policy\n    } else {\n        throw e;\n    }\n}","preventionTips":["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."],"tags":["s3","filesystem","delete","directory"],"backgroundTag":"directory-not-empty","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}