{"record":{"id":"aeb96765ff2ad827","repo":"apache/flink","slug":"directory","errorCode":null,"errorMessage":"{directory}","messagePattern":"\\{directory\\}","errorType":"exception","errorClass":"FileNotFoundException","httpStatus":null,"severity":"warning","filePath":"flink-core/src/main/java/org/apache/flink/util/FileUtils.java","lineNumber":356,"sourceCode":"            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());\n                }\n            }\n\n            // remove all files in the directory\n            for (File file : files) {\n                if (file != null) {\n                    deleteFileOrDirectory(file);\n                }\n            }\n        } else if (directory.exists()) {\n            throw new IOException(directory + \" is not a directory but a regular file\");\n        } else {\n            // else does not exist at all\n            throw new FileNotFoundException(directory.toString());\n        }\n    }\n\n    private static void guardIfNotThreadSafe(ThrowingConsumer<File, IOException> toRun, File file)","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/util/FileUtils.java#L338-L374","documentation":"A FileNotFoundException whose message is just the directory path, thrown from cleanDirectoryInternal when listFiles() returned null and exists() then reported the directory as gone. It means the directory disappeared between the two checks — a benign race with a concurrent deleter, surfaced as an exception.","triggerScenarios":"Two threads/processes concurrently cleaning the same directory: listFiles() fails because the dir is being removed, and by the time exists() runs it is already deleted. Common when a shutdown hook and a supervisor both wipe the same work/temp dir.","commonSituations":"Race between task failure recovery cleanup and JobManager-local cleanup; test teardown running concurrently with async cleanup from the previous test; external janitor scripts deleting the same temp dirs.","solutions":["Serialize cleanup of shared directories (single owner, lock, or sequentialize teardown) so two cleaners never race","Catch FileNotFoundException around deleteDirectory when the race is benign and idempotent deletion is intended","Give each component its own working directory so cleanups cannot collide"],"exampleFix":"// before\nFileUtils.deleteDirectory(sharedWorkDir); // races with other cleaner\n\n// after\ntry {\n    FileUtils.deleteDirectory(sharedWorkDir);\n} catch (FileNotFoundException e) {\n    // already removed concurrently; deletion is idempotent for us\n    LOG.debug(\"Directory already deleted concurrently: {}\", sharedWorkDir);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { FileUtils.deleteDirectory(dir); } catch (FileNotFoundException e) { /* removed concurrently — treat as success */ }","preventionTips":["Give each process/component exclusive ownership of the directories it cleans","Make deletion idempotent in callers: absent directory equals deleted directory"],"tags":["flink-core","filesystem","cleanup","race-condition","concurrency"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}