{"record":{"id":"01e60f402406ec9e","repo":"elastic/elasticsearch","slug":"file-still-exists-after-waits","errorCode":null,"errorMessage":"File still exists after {} waits.","messagePattern":"File still exists after (.+?) waits\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java","lineNumber":1262,"sourceCode":"        } catch (IOException e) {\n            throw new UncheckedIOException(e);\n        } catch (InterruptedException x) {\n            throw new UncheckedIOException(\"Interrupted while deleting.\", new IOException());\n        }\n    }\n\n    // The exception handling here is loathsome, but necessary!\n    private void deleteWithRetry0(Path path) throws IOException, InterruptedException {\n        int times = 0;\n        IOException ioe = null;\n        while (true) {\n            try {\n                fileSystemOperations.delete(d -> d.delete(path));\n                times++;\n                // Checks for absence of the file. Semantics of Files.exists() is not the same.\n                while (Files.notExists(path) == false) {\n                    if (times > MAX_RETRY_DELETE_TIMES) {\n                        throw new IOException(\"File still exists after \" + times + \" waits.\");\n                    }\n                    Thread.sleep(RETRY_DELETE_MILLIS);\n                    // retry\n                    fileSystemOperations.delete(d -> d.delete(path));\n                    times++;\n                }\n                break;\n            } catch (NoSuchFileException ignore) {\n                // already deleted, ignore\n                break;\n            } catch (org.gradle.api.UncheckedIOException | IOException x) {\n                if (x.getCause() instanceof NoSuchFileException) {\n                    // already deleted, ignore\n                    break;\n                }\n                // Backoff/retry in case another process is accessing the file\n                times++;\n                if (ioe == null) ioe = new IOException();","sourceCodeStart":1244,"sourceCodeEnd":1280,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java#L1244-L1280","documentation":"Thrown inside deleteWithRetry0 when, after MAX_RETRY_DELETE_TIMES attempts (15 on Windows, 0 elsewhere), Files.notExists(path) is still false — the file survived every delete call. This is a Windows-specific retry path; on Unix the retry loop is effectively disabled (0 iterations) so this throw is Windows-only in practice.","triggerScenarios":"fileSystemOperations.delete succeeds without throwing but the file remains on disk (or reappears), and Files.notExists stays false for 15 attempts spaced 500ms apart (total ~7.5s). Classic Windows behavior where a file handle is held by another process.","commonSituations":"Antivirus or search indexer holds a handle on a shard/lock file under the testcluster data dir; a child ML/monitoring process is still dying and holds the file; Windows file-delete semantics where the file is marked for deletion but not gone until the last handle closes.","solutions":["Add antivirus exclusions for the gradle build / testclusters directory on Windows.","Ensure all child processes (ML, watchers) are stopped before teardown — check the node's children list in stopHandle.","Close any file explorer / IDE that has the data dir open.","As a last resort, manually delete the leftover path under build/testclusters and re-run."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["On Windows, add antivirus exclusions for the gradle build/testclusters directory.","Ensure all child processes (ML, watchers) are stopped before teardown.","Close any file explorer / IDE window that has the data dir open."],"tags":["testclusters","delete","windows","file-locking"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}