{"record":{"id":"6c54c09151238ef7","repo":"apache/seatunnel","slug":"directory-file-is-not-empty","errorCode":null,"errorMessage":"Directory: ${file} is not empty.","messagePattern":"Directory: (.+?) is not empty\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-file/connector-file-ftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/ftp/system/SeaTunnelFTPFileSystem.java","lineNumber":458,"sourceCode":"     * another method. Otherwise every API invocation incurs the overhead of opening/closing a TCP\n     * connection.\n     */\n    private boolean delete(FTPClient client, Path file, boolean recursive) throws IOException {\n        Path workDir = new Path(client.printWorkingDirectory());\n        Path absolute = makeAbsolute(workDir, file);\n        String pathName = absolute.toUri().getPath();\n        try {\n            FileStatus fileStat = getFileStatus(client, absolute);\n            if (fileStat.isFile()) {\n                return client.deleteFile(pathName);\n            }\n        } catch (FileNotFoundException e) {\n            // the file is not there\n            return false;\n        }\n        FileStatus[] dirEntries = listStatus(client, absolute);\n        if (dirEntries != null && dirEntries.length > 0 && !recursive) {\n            throw new IOException(\"Directory: \" + file + \" is not empty.\");\n        }\n        if (dirEntries != null) {\n            for (int i = 0; i < dirEntries.length; i++) {\n                delete(client, new Path(absolute, dirEntries[i].getPath()), recursive);\n            }\n        }\n        return client.removeDirectory(pathName);\n    }\n\n    private FsAction getFsAction(int accessGroup, FTPFile ftpFile) {\n        FsAction action = FsAction.NONE;\n        if (ftpFile.hasPermission(accessGroup, FTPFile.READ_PERMISSION)) {\n            action.or(FsAction.READ);\n        }\n        if (ftpFile.hasPermission(accessGroup, FTPFile.WRITE_PERMISSION)) {\n            action.or(FsAction.WRITE);\n        }\n        if (ftpFile.hasPermission(accessGroup, FTPFile.EXECUTE_PERMISSION)) {","sourceCodeStart":440,"sourceCodeEnd":476,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-file/connector-file-ftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/ftp/system/SeaTunnelFTPFileSystem.java#L440-L476","documentation":"Thrown by SeaTunnelFTPFileSystem.delete() when the target path is a directory that still contains entries and recursive=false. The FTP filesystem refuses to delete a non-empty directory without the recursive flag to prevent accidental data loss.","triggerScenarios":"Calling fs.delete(dirPath, false) on a directory that lists at least one child entry via listStatus(). Also reached indirectly when delete() recurses or is used internally by create/success cleanup paths.","commonSituations":"Cleaning up an output directory before a job run with overwrite semantics but without recursion; temp/staging directories that were not emptied; users passing recursive=false by default from generic Hadoop FileSystem wrapper code.","solutions":["Call fs.delete(path, true) to delete the directory and all its contents","Delete the child files first, then the now-empty directory","Manually clean the directory on the FTP server if only partial cleanup is intended","Guard the delete call with a check of listStatus() length when you intentionally keep contents"],"exampleFix":"// before\nfs.delete(outputDir, false);\n// after\nfs.delete(outputDir, true); // recursive delete of non-empty directory","handlingStrategy":"validation","validationCode":"FileStatus[] entries = fs.listStatus(dir);\nif (entries.length > 0) {\n    fs.delete(dir, true); // recursive required for non-empty dirs\n} else {\n    fs.delete(dir, false);\n}","typeGuard":null,"tryCatchPattern":"try {\n    fs.delete(dir, false);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"is not empty\")) {\n        fs.delete(dir, true); // escalate to recursive when contents are disposable\n    } else { throw e; }\n}","preventionTips":["Default to recursive=true for directory cleanup unless contents must be preserved","Inspect listStatus() before deleting to decide the recursive flag","Clean temp/staging directories as part of job teardown"],"tags":["ftp","file-delete","directory","io"],"backgroundTag":"directory-not-found","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}