{"record":{"id":"d39a1575c50f5097","repo":"elastic/elasticsearch","slug":"io-error-while-waiting-cluster","errorCode":null,"errorMessage":"IO error while waiting cluster","messagePattern":"IO error while waiting cluster","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchCluster.java","lineNumber":662,"sourceCode":"        waitConditions.put(\"cluster health yellow\", (node) -> {\n            try {\n                boolean httpSslEnabled = getFirstNode().isHttpSslEnabled();\n                WaitForHttpResource wait = new WaitForHttpResource(\n                    httpSslEnabled ? \"https\" : \"http\",\n                    getFirstNode().getHttpSocketURI(),\n                    nodes.size()\n                );\n                if (httpSslEnabled) {\n                    getFirstNode().configureHttpWait(wait);\n                }\n                List<Map<String, String>> credentials = getFirstNode().getCredentials();\n                if (getFirstNode().getCredentials().isEmpty() == false) {\n                    wait.setUsername(credentials.get(0).get(\"useradd\"));\n                    wait.setPassword(credentials.get(0).get(\"-p\"));\n                }\n                return wait.wait(500);\n            } catch (IOException e) {\n                throw new UncheckedIOException(\"IO error while waiting cluster\", e);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                throw new TestClustersException(\"Interrupted while waiting for \" + this, e);\n            } catch (GeneralSecurityException e) {\n                throw new RuntimeException(\"security exception\", e);\n            }\n        });\n    }\n\n    @Nested\n    public NamedDomainObjectContainer<ElasticsearchNode> getNodes() {\n        return nodes;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;","sourceCodeStart":644,"sourceCodeEnd":680,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchCluster.java#L644-L680","documentation":"Wrapped UncheckedIOException thrown from the cluster-health-yellow wait condition in ElasticsearchCluster.addWaitForClusterHealth. It fires when WaitForHttpResource.wait(500) raises an IOException while polling the cluster's HTTP endpoint for yellow health during startup.","triggerScenarios":"The wait condition fails with IOException — the node's HTTP port is unreachable, returns malformed responses, or the connection is reset during the health poll. Original IOException is the cause.","commonSituations":"The node process crashed during boot; HTTP/SSL misconfiguration; the port is bound but the REST layer is not ready; firewall/proxy interference in CI; transient network blips against the loopback wait endpoint.","solutions":["Inspect the wrapped IOException cause — connection refused vs. reset vs. SSL points to different fixes.","Check the node's log in build/testclusters/<cluster>-<n>/logs for the crash that made HTTP unavailable.","Verify HTTP/SSL settings consistency (httpSslEnabled must match the actual node config).","Increase wait robustness via additional waitConditions rather than relying on a single 500ms poll."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-flight: confirm HTTP port is listening before relying on the wait\ntry (Socket s = new Socket()) {\n    s.connect(new InetSocketAddress(node.getHttpSocketURI().getHost(), node.getHttpSocketURI().getPort()), 1000);\n} catch (IOException e) {\n    throw new IllegalStateException(\"Node HTTP port unreachable before wait\", e);\n}","typeGuard":null,"tryCatchPattern":"try {\n    // task that triggers cluster.start() and its wait conditions\n} catch (UncheckedIOException e) {\n    Throwable cause = e.getCause();\n    // inspect cause: connection refused vs SSL vs reset\n    throw cause instanceof java.net.ConnectException\n        ? new IllegalStateException(\"Node failed to bind HTTP — check logs\", cause)\n        : e;\n}","preventionTips":["Inspect node logs immediately on a wait failure (build/testclusters/<cluster>-0/logs).","Verify httpSslEnabled matches the node's SSL configuration.","Add robust wait conditions rather than relying on a single 500ms poll."],"tags":["test","testclusters","io","network","wait-conditions"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}