apache/pulsar · error · RestException

Cannot delete the global namespace ${namespaceName}. There a

Error message

Cannot delete the global namespace ${namespaceName}. There are still more than one replication clusters configured.

What it means

A 412 PRECONDITION_FAILED thrown by internalDeleteNamespaceBundleAsync when deleting an individual namespace bundle of a global namespace whose policies still have more than one replication cluster, so getClusterThatCanDeleteNamespace() returns null. Bundle deletion, like namespace deletion, requires the namespace to be reduced to a single owning cluster first.

Source

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

    @SuppressWarnings("deprecation")
    protected CompletableFuture<Void> internalDeleteNamespaceBundleAsync(String bundleRange, boolean authoritative,
                                                                         boolean force) {
        log.info()
                .attr("namespace", namespaceName)
                .attr("bundleRange", bundleRange)
                .attr("authoritative", authoritative)
                .attr("force", force)
                .log("Deleting namespace bundle");
        return validateNamespaceOperationAsync(namespaceName, NamespaceOperation.DELETE_BUNDLE)
                .thenCompose(__ -> validatePoliciesReadOnlyAccessAsync())
                .thenCompose(__ -> getNamespacePoliciesAsync(namespaceName))
                .thenCompose(policies -> {
                    CompletableFuture<Void> future = CompletableFuture.completedFuture(null);
                    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 "
                                + namespaceName
                                + ". There are still more than one replication clusters configured.");
                    }
                    if (!cluster.equals(config().getClusterName())) {
                        // the only replication cluster is other cluster, redirect
                        future = clusterResources().getClusterAsync(cluster)
                                .thenCompose(clusterData -> {
                                    if (clusterData.isEmpty()) {
                                        throw new RestException(Status.NOT_FOUND,
                                                "Cluster " + cluster + " does not exist");
                                    }
                                    ClusterData replClusterData = clusterData.get();
                                    URL replClusterUrl;
                                    try {
                                        if (!config().isTlsEnabled() || !isRequestHttps()) {
                                            replClusterUrl = new URL(replClusterData.getServiceUrl());
                                        } else if (StringUtils.isNotBlank(replClusterData.getServiceUrlTls())) {
                                            replClusterUrl = new URL(replClusterData.getServiceUrlTls());

View on GitHub (pinned to 820761864e)

Solutions

  1. Narrow replication clusters to one first (POST .../replication with a single cluster), then delete the bundle.
  2. Delete the whole namespace with the documented cluster-narrowing flow instead of per-bundle deletes.
  3. Inspect policies with GET .../replication to confirm the cluster count before bundle operations.
  4. Ensure the remaining single cluster equals config().getClusterName() to avoid redirect paths.

Example fix

// before
curl -X DELETE http://broker:8080/admin/v2/namespaces/t/ns/0x00000000_0xffffffff
// 412

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

Strategy: validation

Validate before calling

const clusters = await admin.namespaces().getNamespaceReplicationClusters(tenant, ns);
if (clusters.length !== 1) {
  throw new Error(`bundle delete requires single replication cluster; current: ${clusters}`);
}

Try / catch

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

Prevention

When it happens

Trigger: DELETE /admin/v2/namespaces/{tenant}/{namespace}/{bundle} where the namespace policy's replication_clusters contains 2+ clusters. Also surfaces when operators try to clear bundles one-by-one as a workaround for the namespace-not-empty guard.

Common situations: Geo-replication cleanup scripts that unload/delete bundles before reducing replication clusters; partially drained namespaces where one cluster was removed but others remain; confusion between bundle-level and namespace-level delete requirements.

Related errors


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