elastic/elasticsearch · critical · TestClustersException

Failed to start ES process for {}

Error message

Failed to start ES process for {}

What it means

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).

Source

Thrown at build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java:940

        // Direct the stderr to the ES log file. This should capture any jvm problems to start.
        // Stdout is discarded because ES duplicates the log file to stdout when run in the foreground.
        processBuilder.redirectOutput(ProcessBuilder.Redirect.appendTo(esOutputFile.toFile()));
        processBuilder.redirectErrorStream(true);

        if (keystorePassword != null && keystorePassword.length() > 0) {
            try {
                Files.writeString(esInputFile, keystorePassword + "\n", StandardOpenOption.CREATE);
                processBuilder.redirectInput(esInputFile.toFile());
            } catch (IOException e) {
                throw new TestClustersException("Failed to set the keystore password for " + this, e);
            }
        }
        LOGGER.info("Running `{}` in `{}` for {} env: {}", command, workingDir, this, environment);
        Process esProcess;
        try {
            esProcess = processBuilder.start();
        } catch (IOException e) {
            throw new TestClustersException("Failed to start ES process for " + this, e);
        }
        testClustersRegistryProvider.get().storeProcess(id(), esProcess);
        reaperServiceProvider.get().registerPid(toString(), esProcess.pid());
    }

    @Internal
    public Path getDistroDir() {
        return canUseSharedDistribution()
            ? getExtractedDistributionDir().toFile().listFiles()[0].toPath()
            : workingDir.resolve("distro").resolve(getVersion() + "-" + testDistribution);
    }

    @Override
    @Internal
    public String getHttpSocketURI() {
        return getHttpPortInternal().get(0);
    }

View on GitHub (pinned to db6a809a66)

Solutions

  1. 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.
  2. Run getDistroDir() manually: confirm the bin/elasticsearch (or bin\elasticsearch.bat on Windows) file exists and is executable under the node's workingDir.
  3. 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.
  4. If on a network/foreign filesystem, ensure the extracted distro dir is on a local filesystem with exec permission (chmod +x bin/elasticsearch).

Example fix

// before: distro dir empty after a partial extract
// verify before start:
Path bin = effectiveDistroDir.resolve("bin/elasticsearch");
if (Files.notExists(bin)) {
    throw new IllegalStateException("Missing ES binary at " + bin + " — re-run the distro extract task");
}
esProcess = processBuilder.start();
Defensive patterns

Strategy: try-catch

Validate before calling

Path bin = effectiveDistroDir.resolve(OS.<String>conditional().onUnix(()->"bin/elasticsearch").onWindows(()->"bin\\elasticsearch.bat").supply());
if (Files.notExists(bin)) {
    throw new IllegalStateException("ES binary missing at " + bin + " — re-extract the distribution");
}

Try / catch

try {
    esProcess = processBuilder.start();
} catch (IOException e) {
    throw new TestClustersException("Failed to start ES process for " + this, e);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/c0d828e25ca9751c. Report an issue: GitHub.