{"record":{"id":"db158990d3fdd805","repo":"elastic/elasticsearch","slug":"s-failed-to-wait-for-s-after-d-s","errorCode":null,"errorMessage":"`%s` failed to wait for %s after %d %s","messagePattern":"`(.+?)` failed to wait for (.+?) after (.+?) (.+?)","errorType":"exception","errorClass":"TestClustersException","httpStatus":null,"severity":"error","filePath":"build-tools/src/main/java/org/elasticsearch/gradle/testclusters/TestClusterConfiguration.java","lineNumber":169,"sourceCode":"                        break;\n                    }\n                } catch (TestClustersException e) {\n                    throw e;\n                } catch (Exception e) {\n                    lastException = e;\n                }\n            }\n            if (conditionMet == false) {\n                String message = String.format(\n                    Locale.ROOT,\n                    \"`%s` failed to wait for %s after %d %s\",\n                    context,\n                    description,\n                    nodeUpTimeout,\n                    nodeUpTimeoutUnit\n                );\n                if (lastException == null) {\n                    throw new TestClustersException(message);\n                } else {\n                    String extraCause = \"\";\n                    Throwable cause = lastException;\n                    int ident = 2;\n                    while (cause != null) {\n                        if (cause.getMessage() != null && cause.getMessage().isEmpty() == false) {\n                            extraCause += \"\\n\" + \" \".repeat(ident) + cause.getMessage();\n                            ident += 2;\n                        }\n                        cause = cause.getCause();\n                    }\n                    throw new TestClustersException(message + extraCause, lastException);\n                }\n            }\n            logger.info(\"{}: {} took {} seconds\", this, description, (System.currentTimeMillis() - thisConditionStartedAt) / 1000.0);\n        });\n    }\n","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/TestClusterConfiguration.java#L151-L187","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: default timeout too short\ntestClusters.c.nodeUpTimeout = 60\n// after\ntestClusters.c.nodeUpTimeout = 180","handlingStrategy":"retry","validationCode":"// Sanity-check timeout against expected startup cost before waiting\nlong estimatedMs = expectedStartupSeconds * 1000L;\nif (nodeUpTimeoutUnit.toMillis(nodeUpTimeout) < estimatedMs) {\n  throw new IllegalStateException(\"nodeUpTimeout likely too low for this cluster shape\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  cluster.waitForConditions(conds, start, timeout, unit, ctx);\n} catch (TestClustersException e) {\n  if (e.getMessage().contains(\"failed to wait\") && e.getCause() == null) {\n    // silent timeout — extend and retry, or investigate readiness\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["gradle","testclusters","timeout","startup","build-tools"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}