elastic/elasticsearch · error · IllegalArgumentException

Cannot shrink {} to have {} nodes as it already has {}

Error message

Cannot shrink {} to have {} nodes as it already has {}

What it means

Thrown by ElasticsearchCluster.setNumberOfNodes when the requested count is smaller than the number of nodes already in the cluster. The list only grows (new ElasticsearchNode entries are appended in the loop below); shrinking is not supported because removing running nodes from a test cluster is unsafe.

Source

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

    public FileCollection getInstalledClasspath() {
        return pluginAndModuleConfiguration.getAsFileTree().filter(f -> f.getName().endsWith(".jar"));
    }

    @InputFiles
    @PathSensitive(PathSensitivity.RELATIVE)
    public FileCollection getInstalledFiles() {
        return pluginAndModuleConfiguration.getAsFileTree().filter(f -> f.getName().endsWith(".jar") == false);
    }

    public void setNumberOfNodes(int numberOfNodes) {
        checkFrozen();

        if (numberOfNodes < 1) {
            throw new IllegalArgumentException("Number of nodes should be >= 1 but was " + numberOfNodes + " for " + this);
        }

        if (numberOfNodes < nodes.size()) {
            throw new IllegalArgumentException(
                "Cannot shrink " + this + " to have " + numberOfNodes + " nodes as it already has " + getNumberOfNodes()
            );
        }

        for (int i = nodes.size(); i < numberOfNodes; i++) {
            this.nodes.add(
                new ElasticsearchNode(
                    safeName(clusterName),
                    path,
                    clusterName + "-" + i,
                    project,
                    reaper,
                    testClustersRegistryProvider,
                    fileSystemOperations,
                    archiveOperations,
                    execOperations,
                    fileOperations,
                    workingDirBase,

View on GitHub (pinned to db6a809a66)

Solutions

  1. Only ever increase numberOfNodes for a given cluster instance; declare separate testClusters blocks if different sizes are needed.
  2. Audit ordering of setNumberOfNodes calls — move the largest required size to the earliest point.
  3. If a smaller cluster is genuinely needed, define a distinct testCluster (e.g. testClusters { small {} }) rather than reusing one.

Example fix

// before
testClusters {
  numberOfNodes = 3
}
tasks.named('integTest').configure {
  // later, in a different task reusing the same cluster
  doFirst { testClusters.cluster.numberOfNodes = 1 }  // throws
}

// after
testClusters {
  big { numberOfNodes = 3 }
  small { numberOfNodes = 1 }
}
tasks.named('integTestBig').configure { useCluster testClusters.big }
tasks.named('integTestSmall').configure { useCluster testClusters.small }
Defensive patterns

Strategy: validation

Validate before calling

int current = cluster.getNumberOfNodes();
if (requested < current) {
    throw new IllegalStateException("Refusing to shrink cluster " + current + " -> " + requested);
}
cluster.setNumberOfNodes(requested);

Prevention

When it happens

Trigger: A cluster already has N nodes (added via prior setNumberOfNodes or node {} blocks) and a later setNumberOfNodes(M) call has M < N.

Common situations: Two test tasks share a cluster spec but request different sizes; a setup hook sets a higher count then a per-test override tries to lower it; dynamic resizing based on a parameter that decreased between runs.

Related errors


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