apache/pulsar · error · RestException

Cluster not empty

Error message

Cluster not empty

What it means

HTTP 412 (PRECONDITION_FAILED) thrown when deleting a cluster that is still referenced by at least one tenant/namespace. internalDeleteClusterAsync first calls isClusterUsedAsync; if any namespace is provisioned on the cluster, deletion is refused to avoid orphaning namespaces. This is the tenant-usage branch of the emptiness check.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/ClustersBase.java:522

                                .log("Failed to delete cluster - Does not exist");
                        asyncResponse.resume(new RestException(Status.NOT_FOUND, "Cluster does not exist"));
                        return null;
                    }
                    log.error()
                            .attr("cluster", cluster)
                            .exception(ex)
                            .log("Failed to delete cluster");
                    resumeAsyncResponseExceptionally(asyncResponse, ex);
                    return null;
                });
    }

    private CompletableFuture<Void> internalDeleteClusterAsync(String cluster) {
        // Check that the cluster is not used by any tenant (eg: no namespaces provisioned there)
        return pulsar().getPulsarResources().getClusterResources().isClusterUsedAsync(cluster)
                .thenCompose(isClusterUsed -> {
                    if (isClusterUsed) {
                        throw new RestException(PRECONDITION_FAILED, "Cluster not empty");
                    }
                    // check the namespaceIsolationPolicies associated with the cluster
                    return namespaceIsolationPolicies().getIsolationDataPoliciesAsync(cluster);
                }).thenCompose(nsIsolationPoliciesOpt -> {
                    if (nsIsolationPoliciesOpt.isPresent()) {
                        if (!nsIsolationPoliciesOpt.get().getPolicies().isEmpty()) {
                            throw new RestException(PRECONDITION_FAILED, "Cluster not empty");
                        }
                        // Need to delete the isolation policies if present
                        return namespaceIsolationPolicies().deleteIsolationDataAsync(cluster);
                    }
                    return CompletableFuture.completedFuture(null);
                }).thenCompose(unused -> clusterResources()
                        .getFailureDomainResources().deleteFailureDomainsAsync(cluster)
                        .thenCompose(__ -> clusterResources().deleteClusterAsync(cluster)));
    }

    @GET

View on GitHub (pinned to 820761864e)

Solutions

  1. Migrate or delete all namespaces on the cluster: for each namespace, either delete it or remove the cluster from its replication clusters / allowed clusters.
  2. Update tenants (PUT /admin/v3/tenants/{tenant}) to drop this cluster from allowedClusters where no namespaces remain.
  3. Run GET /admin/v3/namespaces (filtered by cluster) to enumerate what still references the cluster, then clean up.
  4. Retry DELETE once the cluster is unused.

Example fix

// before
admin.clusters().deleteCluster("old-cluster"); // 412 Cluster not empty
// after
for (String ns : admin.namespaces().getNamespaces("my-tenant")) {
    if (admin.namespaces().getReplicationClusters(ns).contains("old-cluster")) {
        admin.namespaces().deleteNamespace(ns); // or update replication clusters
    }
}
admin.clusters().deleteCluster("old-cluster");
Defensive patterns

Strategy: validation

Validate before calling

// ensure no namespaces/tenants reference the cluster before deleting
for (String ns : admin.namespaces().getNamespaces()) {
    if (admin.namespaces().getReplicationClusters(ns).contains(cluster)) {
        throw new IllegalStateException("Namespace " + ns + " still uses cluster " + cluster);
    }
}
admin.clusters().deleteCluster(cluster);

Try / catch

try {
    admin.clusters().deleteCluster(cluster);
} catch (PulsarAdminException.PreconditionFailedException e) {
    // "Cluster not empty": migrate/delete namespaces referencing it, then retry
}

Prevention

When it happens

Trigger: DELETE /admin/v3/clusters/{cluster} while namespaces or tenants still reference the cluster; decommissioning a cluster before migrating its namespaces; deleting a cluster used in a tenant's allowedCluster list with provisioned namespaces.

Common situations: Cluster teardown runbooks executed out of order; old clusters with forgotten namespaces; replication cluster removal while its local namespaces still exist.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/6ee4a426371be59a. Report an issue: GitHub.