{"record":{"id":"0d16c18889c33f2f","repo":"apache/flink","slug":"directory-is-not-a-directory","errorCode":null,"errorMessage":"{directory} is not a directory","messagePattern":"(.+?) is not a directory","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"flink-core/src/main/java/org/apache/flink/util/FileUtils.java","lineNumber":338,"sourceCode":"            // directory exists and is a directory\n\n            // empty the directory first\n            try {\n                cleanDirectoryInternal(directory);\n            } catch (FileNotFoundException ignored) {\n                // someone concurrently deleted the directory, nothing to do for us\n                return;\n            }\n\n            // delete the directory. this fails if the directory is not empty, meaning\n            // if new files got concurrently created. we want to fail then.\n            // if someone else deleted the empty directory concurrently, we don't mind\n            // the result is the same for us, after all\n            Files.deleteIfExists(directory.toPath());\n        } else if (directory.exists()) {\n            // exists but is file, not directory\n            // either an error from the caller, or concurrently a file got created\n            throw new IOException(directory + \" is not a directory\");\n        }\n        // else: does not exist, which is okay (as if deleted)\n    }\n\n    private static void cleanDirectoryInternal(File directory) throws IOException {\n        if (Files.isSymbolicLink(directory.toPath())) {\n            // the user directories which symbolic links point to should not be cleaned.\n            return;\n        }\n        if (directory.isDirectory()) {\n            final File[] files = directory.listFiles();\n\n            if (files == null) {\n                // directory does not exist any more or no permissions\n                if (directory.exists()) {\n                    throw new IOException(\"Failed to list contents of \" + directory);\n                } else {\n                    throw new FileNotFoundException(directory.toString());","sourceCodeStart":320,"sourceCodeEnd":356,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/util/FileUtils.java#L320-L356","documentation":"Thrown by FileUtils.deleteDirectory when the given path exists but is a regular file. deleteDirectory is only meaningful for directories; deleting a file at that path would exceed the caller's intent, so it fails fast instead of guessing.","triggerScenarios":"Calling FileUtils.deleteDirectory(file) where file exists and isFile() is true; a typical case is a path that used to be a directory but a concurrent process recreated it as a file, or the caller mixed up deleteFileOrDirectory and deleteDirectory.","commonSituations":"Cleanup code assuming a workspace path is always a directory; races where another process replaced the directory with a symlink target/file; tests pointing cleanup at a file artifact by mistake.","solutions":["Check whether the path should really be a directory; if it may be either, use deleteFileOrDirectory instead","Remove the stale file manually or via a pre-clean step, then rerun","Investigate what created a file where a directory was expected — that is usually the actual bug"],"exampleFix":"// before\nFileUtils.deleteDirectory(new File(path)); // path is a file\n\n// after\nFile f = new File(path);\nif (f.isDirectory()) {\n    FileUtils.deleteDirectory(f);\n} else if (f.exists()) {\n    // deliberate: only files ever expected here\n    org.apache.flink.util.Preconditions.checkState(!f.isDirectory(), path);\n    f.delete();\n}","handlingStrategy":"type-guard","validationCode":"File f = new File(path);\nif (f.exists() && !f.isDirectory()) {\n    throw new IOException(\"Expected directory, found file: \" + f);\n}","typeGuard":"static boolean isDeletableDirectory(File f) { return !f.exists() || f.isDirectory(); }","tryCatchPattern":"catch (IOException e) when cleaning best-effort: log and continue if cleanup is non-critical.","preventionTips":["Use deleteFileOrDirectory when the path's type is genuinely unknown","Investigate anything creating a file where your code expects a directory — that is the real defect"],"tags":["flink-core","filesystem","cleanup","validation"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}