elastic/elasticsearch · critical · TestClustersException
Can not start {}, missing: {}
Error message
Can not start {}, missing: {} What it means
TestClustersException thrown at the top of ElasticsearchNode.start() when the extracted distribution directory does not exist. start() requires the ES distribution to have been downloaded/unpacked into getExtractedDistributionDir(); its absence means the distribution-resolution step did not run or failed.
Source
Thrown at build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java:472
public void freeze() {
requireNonNull(testDistribution, "null testDistribution passed when configuring test cluster `" + this + "`");
LOGGER.info("Locking configuration of `{}`", this);
distributions.forEach(ElasticsearchDistribution::maybeFreeze);
configurationFrozen.set(true);
}
private static String throwableToString(Throwable t) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
return sw.toString();
}
@Override
public synchronized void start() {
LOGGER.info("Starting `{}`", this);
if (Files.exists(getExtractedDistributionDir()) == false) {
throw new TestClustersException("Can not start " + this + ", missing: " + getExtractedDistributionDir());
}
if (Files.isDirectory(getExtractedDistributionDir()) == false) {
throw new TestClustersException("Can not start " + this + ", is not a directory: " + getExtractedDistributionDir());
}
try {
if (isWorkingDirConfigured == false) {
logToProcessStdout("Configuring working directory: " + workingDir);
// make sure we always start fresh
if (Files.exists(workingDir)) {
if (preserveDataDir) {
try (var files = Files.list(workingDir)) {
files.filter(path -> path.equals(confPathData) == false).forEach(this::uncheckedDeleteWithRetry);
}
} else {
deleteWithRetry(workingDir);
}
}View on GitHub (pinned to db6a809a66)
Solutions
- Ensure start() is invoked through the testclusters lifecycle (useCluster / dependsOn wiring) so the extraction task runs first.
- Check the path printed in the message; if missing, run the distro-extraction task (e.g. ./gradlew <taskName>Download) or clean and re-run.
- Verify the distribution version/type resolves — inspect testDistribution and the version configuration; check network/auth for snapshot distributions.
- If working dir was wiped, remove build/testclusters and rerun the test to re-trigger extraction.
Example fix
// before
tasks.register('customStart') {
doFirst { testClusters.cluster.singleNode().start() } // distro not extracted yet
}
// after
tasks.register('customStart') {
dependsOn testClusters.cluster // ensures extraction runs first
doFirst { testClusters.cluster.singleNode().start() }
} Defensive patterns
Strategy: validation
Validate before calling
Path distro = node.getExtractedDistributionDir();
if (!Files.isDirectory(distro)) {
throw new IllegalStateException("Distribution not extracted at " + distro
+ " — dependsOn the extraction task first");
}
node.start(); Try / catch
try {
node.start();
} catch (TestClustersException e) {
if (e.getMessage().contains("missing")) {
// trigger extraction then retry once
throw new IllegalStateException("Distribution missing — rerun extraction task", e);
}
throw e;
} Prevention
- Always wire dependsOn the distribution-extraction task before calling start().
- Use the testclusters lifecycle (useCluster) rather than manual start() calls.
- Don't wipe build/testclusters between tasks in the same run.
When it happens
Trigger: node.start() is called but Files.exists(getExtractedDistributionDir()) is false — the archive was never fetched/extracted, was deleted, or extraction ran in a different working dir.
Common situations: A custom test task invokes start() without depending on the distribution-extraction task; the build/testclusters dir was cleaned mid-run; the distribution could not be resolved (auth, network, wrong version) and the dir was never populated; the path points outside the project workspace.
Related errors
- Cannot add nodes to test cluster after is has been frozen
- Configuration for {} can not be altered, already locked
- Number of nodes should be >= 1 but was {} for {}
- Cannot shrink {} to have {} nodes as it already has {}
- Ran out of nodes to take to the next version
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/e9b9d6825ccab7b1.
Report an issue: GitHub.