elastic/elasticsearch · error · TestClustersException
`%s` failed to wait for %s after %d %s
Error message
`%s` failed to wait for %s after %d %s
What it means
Thrown by waitForConditions() when the wait loop exhausts the `nodeUpTimeout` (in `nodeUpTimeoutUnit`) WITHOUT the condition ever becoming true AND with `lastException == null` — meaning the predicate simply never returned true but also never threw. The message formats the cluster, the condition description, the timeout value, and the unit. This is the 'silent timeout' variant (the variant with a captured exception is #109).
Source
Thrown at build-tools/src/main/java/org/elasticsearch/gradle/testclusters/TestClusterConfiguration.java:169
break;
}
} catch (TestClustersException e) {
throw e;
} catch (Exception e) {
lastException = e;
}
}
if (conditionMet == false) {
String message = String.format(
Locale.ROOT,
"`%s` failed to wait for %s after %d %s",
context,
description,
nodeUpTimeout,
nodeUpTimeoutUnit
);
if (lastException == null) {
throw new TestClustersException(message);
} else {
String extraCause = "";
Throwable cause = lastException;
int ident = 2;
while (cause != null) {
if (cause.getMessage() != null && cause.getMessage().isEmpty() == false) {
extraCause += "\n" + " ".repeat(ident) + cause.getMessage();
ident += 2;
}
cause = cause.getCause();
}
throw new TestClustersException(message + extraCause, lastException);
}
}
logger.info("{}: {} took {} seconds", this, description, (System.currentTimeMillis() - thisConditionStartedAt) / 1000.0);
});
}
View on GitHub (pinned to db6a809a66)
Solutions
- Raise the timeout via the testclusters DSL (e.g. `nodeUpTimeout` / `waitForCondition` timeout parameter) to accommodate slow hosts.
- Inspect the node log to see what state it was in when the timeout fired — was it close to ready or stuck?
- Reduce startup work (fewer plugins, smaller index bootstrap) if the timeout can't be raised.
- Run on a less loaded host; check for GC pauses or CPU starvation.
Example fix
// before: default timeout too short testClusters.c.nodeUpTimeout = 60 // after testClusters.c.nodeUpTimeout = 180
Defensive patterns
Strategy: retry
Validate before calling
// Sanity-check timeout against expected startup cost before waiting
long estimatedMs = expectedStartupSeconds * 1000L;
if (nodeUpTimeoutUnit.toMillis(nodeUpTimeout) < estimatedMs) {
throw new IllegalStateException("nodeUpTimeout likely too low for this cluster shape");
} Try / catch
try {
cluster.waitForConditions(conds, start, timeout, unit, ctx);
} catch (TestClustersException e) {
if (e.getMessage().contains("failed to wait") && e.getCause() == null) {
// silent timeout — extend and retry, or investigate readiness
}
throw e;
} Prevention
- Size `nodeUpTimeout` to the slowest expected host (CI, cold caches, plugin-heavy).
- Profile normal startup time on target hosts and set the timeout with headroom.
- Reduce startup work (fewer plugins, smaller bootstrap) when the timeout can't grow.
When it happens
Trigger: A readiness predicate (e.g. 'HTTP returns 200', 'cluster health yellow') polled until `nodeUpTimeout` elapsed without ever succeeding, and the predicate never threw — it just kept returning false. Typical for slow startup where the node is alive but the endpoint stays non-ready.
Common situations: Default `nodeUpTimeout` too low for a cold start or plugin-heavy cluster; node stuck in a long GC; network/DNS slowness on the readiness socket; a plugin's REST endpoint slow to register; system under heavy load extending startup beyond the configured window.
Related errors
- process was found dead while waiting for {}, {}
- Task {} is not configured to use any clusters. Be sure to ca
- Elasticsearch cluster died
- Can not use {} with {}
- Cannot specify more than one trust method (CA=%s, trustStore
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/db158990d3fdd805.
Report an issue: GitHub.