{"record":{"id":"c215fe9c0687d547","repo":"elastic/elasticsearch","slug":"can-not-start-is-not-a-directory","errorCode":null,"errorMessage":"Can not start {}, is not a directory: {}","messagePattern":"Can not start (.+?), is not a directory: (.+?)","errorType":"exception","errorClass":"TestClustersException","httpStatus":null,"severity":"error","filePath":"build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java","lineNumber":475,"sourceCode":"        distributions.forEach(ElasticsearchDistribution::maybeFreeze);\n        configurationFrozen.set(true);\n    }\n\n    private static String throwableToString(Throwable t) {\n        StringWriter sw = new StringWriter();\n        PrintWriter pw = new PrintWriter(sw);\n        t.printStackTrace(pw);\n        return sw.toString();\n    }\n\n    @Override\n    public synchronized void start() {\n        LOGGER.info(\"Starting `{}`\", this);\n        if (Files.exists(getExtractedDistributionDir()) == false) {\n            throw new TestClustersException(\"Can not start \" + this + \", missing: \" + getExtractedDistributionDir());\n        }\n        if (Files.isDirectory(getExtractedDistributionDir()) == false) {\n            throw new TestClustersException(\"Can not start \" + this + \", is not a directory: \" + getExtractedDistributionDir());\n        }\n\n        try {\n            if (isWorkingDirConfigured == false) {\n                logToProcessStdout(\"Configuring working directory: \" + workingDir);\n                // make sure we always start fresh\n                if (Files.exists(workingDir)) {\n                    if (preserveDataDir) {\n                        try (var files = Files.list(workingDir)) {\n                            files.filter(path -> path.equals(confPathData) == false).forEach(this::uncheckedDeleteWithRetry);\n                        }\n                    } else {\n                        deleteWithRetry(workingDir);\n                    }\n                }\n                isWorkingDirConfigured = true;\n            }\n            setupNodeDistribution(getExtractedDistributionDir());","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java#L457-L493","documentation":"Thrown by ElasticsearchNode.start() after confirming the extracted distribution path exists but Files.isDirectory() returns false. The node refuses to boot because the extraction target is a regular file or a broken symlink rather than an unpacked ES home directory. It is a hard precondition guarding every downstream step that walks the distro tree (setupNodeDistribution, bin scripts, lib/modules).","triggerScenarios":"Calling testClusters.start() (directly or via a TestClustersTask) when getExtractedDistributionDir() resolves to a file, a stale marker file, or a partially extracted archive whose top-level entry was not a directory. Also when a custom distribution download produced a single artifact instead of an unpacked tree, or a previous run left a corrupt extraction behind.","commonSituations":"Interrupted/cancelled Gradle build left a half-extracted distribution. Distribution plugin misconfigured to a 'tar'/'zip' type whose extraction step was skipped. Symlink in the build dir pointing to a deleted target. Manual tampering with build/testclusters/. Stale caches after switching distribution type or OS.","solutions":["Delete the affected node's working/extracted directory (e.g. rm -rf build/testclusters/<node>) and rerun so the distribution is re-extracted.","Check the distribution configuration: ensure the ElasticsearchDistribution type is one that unpacks to a directory (integ-test-zip or archive types that get extracted), not a raw file artifact.","Verify the distribution download/extraction task ran successfully upstream; inspect the path printed in the message with ls -la to see whether it is a file or a dangling symlink.","Run with --rerun-tasks or clean the testclusters task to force re-extraction."],"exampleFix":"// before: distribution produces a single file, not an unpacked dir\ntestClusters {\n  myNode {\n    distribution 'elasticsearch', '8.0.0' // wrong type\n  }\n}\n// after: use the integ-test distribution which extracts to a directory\ntestClusters {\n  myNode {\n    distribution 'integ-test-zip', '8.0.0'\n  }\n}","handlingStrategy":"validation","validationCode":"// Run before start() to confirm the extracted distro is a directory\nPath distroDir = node.getExtractedDistributionDir();\nif (!Files.isDirectory(distroDir)) {\n    throw new IllegalStateException(\"Extracted distro not a directory: \" + distroDir\n        + \" (exists=\" + Files.exists(distroDir) + \"). Clean build/testclusters and rerun.\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not delete parts of build/testclusters by hand; use the Gradle clean task so extraction state stays consistent.","Pin the distribution type to integ-test-zip (or another directory-extracting type) in test cluster config.","On CI, start from a clean workspace or use --rerun-tasks when distribution artifacts change."],"tags":["testclusters","distribution","filesystem","startup"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}