{"record":{"id":"c0d828e25ca9751c","repo":"elastic/elasticsearch","slug":"failed-to-start-es-process-for","errorCode":null,"errorMessage":"Failed to start ES process for {}","messagePattern":"Failed to start ES process for (.+?)","errorType":"exception","errorClass":"TestClustersException","httpStatus":null,"severity":"critical","filePath":"build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java","lineNumber":940,"sourceCode":"        // Direct the stderr to the ES log file. This should capture any jvm problems to start.\n        // Stdout is discarded because ES duplicates the log file to stdout when run in the foreground.\n        processBuilder.redirectOutput(ProcessBuilder.Redirect.appendTo(esOutputFile.toFile()));\n        processBuilder.redirectErrorStream(true);\n\n        if (keystorePassword != null && keystorePassword.length() > 0) {\n            try {\n                Files.writeString(esInputFile, keystorePassword + \"\\n\", StandardOpenOption.CREATE);\n                processBuilder.redirectInput(esInputFile.toFile());\n            } catch (IOException e) {\n                throw new TestClustersException(\"Failed to set the keystore password for \" + this, e);\n            }\n        }\n        LOGGER.info(\"Running `{}` in `{}` for {} env: {}\", command, workingDir, this, environment);\n        Process esProcess;\n        try {\n            esProcess = processBuilder.start();\n        } catch (IOException e) {\n            throw new TestClustersException(\"Failed to start ES process for \" + this, e);\n        }\n        testClustersRegistryProvider.get().storeProcess(id(), esProcess);\n        reaperServiceProvider.get().registerPid(toString(), esProcess.pid());\n    }\n\n    @Internal\n    public Path getDistroDir() {\n        return canUseSharedDistribution()\n            ? getExtractedDistributionDir().toFile().listFiles()[0].toPath()\n            : workingDir.resolve(\"distro\").resolve(getVersion() + \"-\" + testDistribution);\n    }\n\n    @Override\n    @Internal\n    public String getHttpSocketURI() {\n        return getHttpPortInternal().get(0);\n    }\n","sourceCodeStart":922,"sourceCodeEnd":958,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java#L922-L958","documentation":"Thrown by ElasticsearchNode.startElasticsearchProcess when ProcessBuilder.start() fails with an IOException while launching the Elasticsearch JVM for a testcluster. This is a build-time failure: the Gradle testclusters plugin could not even spawn the bin/elasticsearch process, so no node ever comes up. The wrapped IOException usually names the OS-level cause (ENOENT, EACCES, ENOEXEC).","triggerScenarios":"ProcessBuilder.start() throws IOException when the command path (effectiveDistroDir/bin/elasticsearch) does not exist, is not executable, the working directory is invalid, or the OS refuses the spawn (e.g. too many open files, permission denied). Happens after the distro is extracted and config written, at the moment processBuilder.start() is called on line 938.","commonSituations":"Distribution archive was not extracted (canUseSharedDistribution() pointed at an empty getExtractedDistributionDir()), the bin/elasticsearch script lost its +x bit after a tar/cp on a foreign filesystem, ES_PATH_ENV or getESEnvironment() produced a broken environment, running on Windows where the bin\\elasticsearch.bat path is wrong, or a clean checkout where the distro build task was skipped.","solutions":["Check the wrapped IOException's message in the stack trace for the OS error (No such file or directory, Permission denied) and fix that specifically.","Run getDistroDir() manually: confirm the bin/elasticsearch (or bin\\elasticsearch.bat on Windows) file exists and is executable under the node's workingDir.","Re-extract/rebuild the distribution: run the relevant distribution build task (e.g. :distribution:docker:docker-extract) or delete the testclusters working dir so the distro is re-extracted.","If on a network/foreign filesystem, ensure the extracted distro dir is on a local filesystem with exec permission (chmod +x bin/elasticsearch)."],"exampleFix":"// before: distro dir empty after a partial extract\n// verify before start:\nPath bin = effectiveDistroDir.resolve(\"bin/elasticsearch\");\nif (Files.notExists(bin)) {\n    throw new IllegalStateException(\"Missing ES binary at \" + bin + \" — re-run the distro extract task\");\n}\nesProcess = processBuilder.start();","handlingStrategy":"try-catch","validationCode":"Path bin = effectiveDistroDir.resolve(OS.<String>conditional().onUnix(()->\"bin/elasticsearch\").onWindows(()->\"bin\\\\elasticsearch.bat\").supply());\nif (Files.notExists(bin)) {\n    throw new IllegalStateException(\"ES binary missing at \" + bin + \" — re-extract the distribution\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    esProcess = processBuilder.start();\n} catch (IOException e) {\n    throw new TestClustersException(\"Failed to start ES process for \" + this, e);\n}","preventionTips":["Always run the relevant distribution-extract task before tests that use testclusters.","Keep the testclusters working dir on a local filesystem with exec permission.","On Windows, verify bin\\\\elasticsearch.bat exists after extraction."],"tags":["testclusters","process-launch","gradle","distribution"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}