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)));
}
@GETView on GitHub (pinned to 820761864e)
Solutions
- Migrate or delete all namespaces on the cluster: for each namespace, either delete it or remove the cluster from its replication clusters / allowed clusters.
- Update tenants (PUT /admin/v3/tenants/{tenant}) to drop this cluster from allowedClusters where no namespaces remain.
- Run GET /admin/v3/namespaces (filtered by cluster) to enumerate what still references the cluster, then clean up.
- 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
- Order teardown: namespaces -> tenants' allowedClusters -> isolation policies -> cluster.
- Audit replication-cluster references across all namespaces before decommissioning.
- Automate the enumeration of referencing namespaces in deletion runbooks.
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
- Cluster ${cluster} does not exist.
- Exceed the maximum number of namespace in tenant :${tenant}
- Namespace does not exist
- ResourceGroup is in use
- Namespace does not exist
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/6ee4a426371be59a.
Report an issue: GitHub.