{"record":{"id":"f9d7a61da6d92c09","repo":"apache/pulsar","slug":"cannot-delete-the-global-namespace-nsname-ther","errorCode":null,"errorMessage":"Cannot delete the global namespace ${nsName}. There are still more than one replication clusters configured or replication clusters is empty.","messagePattern":"Cannot delete the global namespace (.+?)\\. There are still more than one replication clusters configured or replication clusters is empty\\.","errorType":"http","errorClass":"RestException","httpStatus":412,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java","lineNumber":494,"sourceCode":"                validateTenantOperationAsync(nsName.getTenant(), TenantOperation.DELETE_NAMESPACE)\n                        .thenCompose(__ -> validatePoliciesReadOnlyAccessAsync())\n                        .thenCompose(__ -> {\n                            if (force && !pulsar().getConfiguration().isForceDeleteNamespaceAllowed()) {\n                                throw new RestException(Status.METHOD_NOT_ALLOWED,\n                                        \"Broker doesn't allow forced deletion of namespaces\");\n                            }\n                            return CompletableFuture.completedFuture(null);\n                        })\n                        .thenCompose(__ -> namespaceResources().getPoliciesAsync(nsName))\n                        .thenCompose(policiesOpt -> {\n                            if (policiesOpt.isEmpty()) {\n                                throw new RestException(Status.NOT_FOUND, \"Namespace \" + nsName + \" does not exist.\");\n                            }\n                            Policies policies = policiesOpt.get();\n                            String cluster = policies.getClusterThatCanDeleteNamespace();\n                            if (cluster == null) {\n                                // There are still more than one clusters configured for the global namespace\n                                throw new RestException(Status.PRECONDITION_FAILED,\n                                    \"Cannot delete the global namespace \" + nsName + \". There are still more than \"\n                                    + \"one replication clusters configured or replication clusters is empty.\");\n                            }\n                            if (!cluster.equals(config().getClusterName())) {\n                                // the only replication cluster is other cluster, redirect\n                                return clusterResources().getClusterAsync(cluster)\n                                        .thenCompose(replClusterDataOpt -> {\n                                            ClusterData replClusterData = replClusterDataOpt\n                                                    .orElseThrow(() -> new RestException(Status.NOT_FOUND,\n                                                            \"Cluster \" + cluster + \" does not exist\"));\n                                            URL replClusterUrl;\n                                            try {\n                                                if (!replClusterData.isBrokerClientTlsEnabled()) {\n                                                    replClusterUrl = new URL(replClusterData.getServiceUrl());\n                                                } else if (StringUtils.isNotBlank(replClusterData.getServiceUrlTls())) {\n                                                    replClusterUrl = new URL(replClusterData.getServiceUrlTls());\n                                                } else {\n                                                    throw new RestException(Status.PRECONDITION_FAILED,","sourceCodeStart":476,"sourceCodeEnd":512,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java#L476-L512","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Reduce replication clusters to exactly one first: POST /admin/v2/namespaces/{tenant}/{namespace}/replication with a single-cluster body, then delete the namespace.","If clusters are drained intentionally, ensure the remaining single cluster matches the broker you call, otherwise expect a redirect (error 94/97 path).","Do not set the replication list to empty to 'prepare' for deletion — that also triggers this error; remove namespaces per cluster instead.","Check the effective policies via GET /admin/v2/namespaces/{tenant}/{namespace}/replication to confirm current cluster set."],"exampleFix":"// before\ncurl -X POST http://broker:8080/admin/v2/namespaces/t/ns/replication -d '[]'\ncurl -X DELETE http://broker:8080/admin/v2/namespaces/t/ns\n// 412\n\n// after\ncurl -X POST http://broker:8080/admin/v2/namespaces/t/ns/replication -d '[\"us-west\"]'\ncurl -X DELETE http://broker:8080/admin/v2/namespaces/t/ns","handlingStrategy":"validation","validationCode":"const clusters = await admin.namespaces().getNamespaceReplicationClusters(tenant, ns);\nif (clusters.length !== 1) {\n  throw new Error(`reduce replication clusters to exactly one before delete, got: ${clusters}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await admin.namespaces().deleteNamespace(tenant, ns);\n} catch (e) {\n  if (e.getStatusCode() === 412) {\n    await admin.namespaces().setNamespaceReplicationClusters(tenant, ns, ['local']);\n    await admin.namespaces().deleteNamespace(tenant, ns);\n  } else throw e;\n}","preventionTips":["Always narrow replication_clusters to one before deleting global namespaces","Never set replication list to empty as a 'pre-delete' step","Check policies with GET .../replication before delete in scripts"],"tags":["pulsar","geo-replication","namespace-deletion","precondition"],"backgroundTag":"replication-clusters-remaining","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}