elastic/elasticsearch · error · IllegalStateException

Can't treat {} as single node as it has {} nodes

Error message

Can't treat {} as single node as it has {} nodes

What it means

Thrown by ElasticsearchCluster.singleNode() when the cluster does not have exactly one node. singleNode() returns the sole ElasticsearchNode for single-node convenience APIs; calling it on a multi-node (or zero-node) cluster is ambiguous and rejected.

Source

Thrown at build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchCluster.java:638

    @Internal
    public List<String> getLeakMessages() {
        return nodes.stream().map(ElasticsearchNode::getLeakMessage).filter(Objects::nonNull).toList();
    }

    @Override
    public void setNameCustomization(Function<String, String> nameCustomization) {
        nodes.all(each -> each.setNameCustomization(nameCustomization));
    }

    @Override
    @Internal
    public boolean isProcessAlive() {
        return nodes.stream().noneMatch(node -> node.isProcessAlive() == false);
    }

    public ElasticsearchNode singleNode() {
        if (nodes.size() != 1) {
            throw new IllegalStateException("Can't treat " + this + " as single node as it has " + nodes.size() + " nodes");
        }
        return getFirstNode();
    }

    private void addWaitForClusterHealth() {
        waitConditions.put("cluster health yellow", (node) -> {
            try {
                boolean httpSslEnabled = getFirstNode().isHttpSslEnabled();
                WaitForHttpResource wait = new WaitForHttpResource(
                    httpSslEnabled ? "https" : "http",
                    getFirstNode().getHttpSocketURI(),
                    nodes.size()
                );
                if (httpSslEnabled) {
                    getFirstNode().configureHttpWait(wait);
                }
                List<Map<String, String>> credentials = getFirstNode().getCredentials();
                if (getFirstNode().getCredentials().isEmpty() == false) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Ensure the cluster is configured with numberOfNodes = 1 before calling singleNode().
  2. If multi-node, iterate getNodes() instead of calling singleNode().
  3. Add a guard at test entry: assumeTrue(cluster.getNodes().size() == 1) when the test requires single-node semantics.

Example fix

// before
testClusters { cluster { numberOfNodes = 3 } }
ElasticsearchNode n = testClusters.cluster.singleNode();  // throws

// after (single-node)
testClusters { cluster { numberOfNodes = 1 } }
ElasticsearchNode n = testClusters.cluster.singleNode();

// after (multi-node)
testClusters.cluster.getNodes().forEach(n -> { ... });
Defensive patterns

Strategy: validation

Validate before calling

if (cluster.getNodes().size() != 1) {
    throw new IllegalStateException("singleNode() requires exactly 1 node, has " + cluster.getNodes().size());
}
ElasticsearchNode n = cluster.singleNode();

Prevention

When it happens

Trigger: Calling cluster.singleNode() when nodes.size() != 1 — either before any nodes are added, or after configuring a multi-node cluster.

Common situations: A test helper assumes a single-node cluster but the test cluster was configured with numberOfNodes > 1, or singleNode() is called early before node sizing has completed.

Related errors


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