apache/pulsar · error · RestException

Cannot delete the global namespace ${nsName}. There are stil

Error message

Cannot delete the global namespace ${nsName}. There are still more than one replication clusters configured or replication clusters is empty.

What it means

A 412 PRECONDITION_FAILED thrown when deleting a global namespace whose policies still resolve to more than one replication cluster, or to an empty replication cluster set — policies.getClusterThatCanDeleteNamespace() returns null in both cases. The broker only allows deleting a global namespace when exactly one replication cluster remains and it is safe to proceed.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java:494

                validateTenantOperationAsync(nsName.getTenant(), TenantOperation.DELETE_NAMESPACE)
                        .thenCompose(__ -> validatePoliciesReadOnlyAccessAsync())
                        .thenCompose(__ -> {
                            if (force && !pulsar().getConfiguration().isForceDeleteNamespaceAllowed()) {
                                throw new RestException(Status.METHOD_NOT_ALLOWED,
                                        "Broker doesn't allow forced deletion of namespaces");
                            }
                            return CompletableFuture.completedFuture(null);
                        })
                        .thenCompose(__ -> namespaceResources().getPoliciesAsync(nsName))
                        .thenCompose(policiesOpt -> {
                            if (policiesOpt.isEmpty()) {
                                throw new RestException(Status.NOT_FOUND, "Namespace " + nsName + " does not exist.");
                            }
                            Policies policies = policiesOpt.get();
                            String cluster = policies.getClusterThatCanDeleteNamespace();
                            if (cluster == null) {
                                // There are still more than one clusters configured for the global namespace
                                throw new RestException(Status.PRECONDITION_FAILED,
                                    "Cannot delete the global namespace " + nsName + ". There are still more than "
                                    + "one replication clusters configured or replication clusters is empty.");
                            }
                            if (!cluster.equals(config().getClusterName())) {
                                // the only replication cluster is other cluster, redirect
                                return clusterResources().getClusterAsync(cluster)
                                        .thenCompose(replClusterDataOpt -> {
                                            ClusterData replClusterData = replClusterDataOpt
                                                    .orElseThrow(() -> new RestException(Status.NOT_FOUND,
                                                            "Cluster " + cluster + " does not exist"));
                                            URL replClusterUrl;
                                            try {
                                                if (!replClusterData.isBrokerClientTlsEnabled()) {
                                                    replClusterUrl = new URL(replClusterData.getServiceUrl());
                                                } else if (StringUtils.isNotBlank(replClusterData.getServiceUrlTls())) {
                                                    replClusterUrl = new URL(replClusterData.getServiceUrlTls());
                                                } else {
                                                    throw new RestException(Status.PRECONDITION_FAILED,

View on GitHub (pinned to 820761864e)

Solutions

  1. Reduce replication clusters to exactly one first: POST /admin/v2/namespaces/{tenant}/{namespace}/replication with a single-cluster body, then delete the namespace.
  2. If clusters are drained intentionally, ensure the remaining single cluster matches the broker you call, otherwise expect a redirect (error 94/97 path).
  3. Do not set the replication list to empty to 'prepare' for deletion — that also triggers this error; remove namespaces per cluster instead.
  4. Check the effective policies via GET /admin/v2/namespaces/{tenant}/{namespace}/replication to confirm current cluster set.

Example fix

// before
curl -X POST http://broker:8080/admin/v2/namespaces/t/ns/replication -d '[]'
curl -X DELETE http://broker:8080/admin/v2/namespaces/t/ns
// 412

// after
curl -X POST http://broker:8080/admin/v2/namespaces/t/ns/replication -d '["us-west"]'
curl -X DELETE http://broker:8080/admin/v2/namespaces/t/ns
Defensive patterns

Strategy: validation

Validate before calling

const clusters = await admin.namespaces().getNamespaceReplicationClusters(tenant, ns);
if (clusters.length !== 1) {
  throw new Error(`reduce replication clusters to exactly one before delete, got: ${clusters}`);
}

Try / catch

try {
  await admin.namespaces().deleteNamespace(tenant, ns);
} catch (e) {
  if (e.getStatusCode() === 412) {
    await admin.namespaces().setNamespaceReplicationClusters(tenant, ns, ['local']);
    await admin.namespaces().deleteNamespace(tenant, ns);
  } else throw e;
}

Prevention

When it happens

Trigger: DELETE /admin/v2/namespaces/{tenant}/{namespace} where the namespace policy's replication_clusters still contains 2+ clusters, or where replication_clusters is empty, so no single owning cluster can be determined.

Common situations: Geo-replicated namespaces where replication was never narrowed down before deletion; automation that unsets replication clusters to empty instead of reducing to one; operators unaware global namespaces must be drained cluster-by-cluster.

Related errors


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