apache/pulsar · error · RestException

Broker doesn't allow forced deletion of namespaces

Error message

Broker doesn't allow forced deletion of namespaces

What it means

A 405 METHOD_NOT_ALLOWED thrown during precheckWhenDeleteNamespace when a namespace delete is requested with force=true but the broker's isForceDeleteNamespaceAllowed configuration is false (the default). The broker intentionally refuses force deletion of namespaces as a data-safety guard; callers must either disable forcing or enable the broker-level allowance.

Source

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

            log.error()
                    .exception(ex)
                    .log("Get admin client error when preparing to delete topics.");
            return FutureUtil.failedFuture(ex);
        }
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        for (String topicName : topicNames) {
            futures.add(admin.topics().deleteAsync(topicName, true));
        }
        return FutureUtil.waitForAll(futures);
    }

    private CompletableFuture<Policies> precheckWhenDeleteNamespace(NamespaceName nsName, boolean force) {
        CompletableFuture<Policies> preconditionCheck =
                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())) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Set forceDeleteNamespaceAllowed=true in broker.conf / the broker.conf of the target cluster if force deletion is intended policy.
  2. Remove force=true from the delete request and delete topics explicitly first (safer).
  3. Apply the config via broker admin/configmanager endpoint or Helm values if running on Kubernetes, then retry.
  4. Verify which cluster you are hitting — a redirect to another cluster may surface a broker with a different force-delete policy.

Example fix

# before (broker.conf)
forceDeleteNamespaceAllowed=false

# after
forceDeleteNamespaceAllowed=true
# then retry:
curl -X DELETE 'http://broker:8080/admin/v2/namespaces/my-tenant/my-ns?force=true'
Defensive patterns

Strategy: validation

Validate before calling

// check broker policy before sending force delete
const ok = await fetch(`${baseUrl}/admin/v2/broker-runtime`);
// or simply omit force unless you've confirmed forceDeleteNamespaceAllowed=true in broker.conf

Try / catch

try {
  await admin.namespaces().deleteNamespace(tenant, ns, true);
} catch (e) {
  if (e.getStatusCode() === 405) {
    // fall back to non-forced deletion after draining topics
  } else throw e;
}

Prevention

When it happens

Trigger: Calling DELETE /admin/v2/namespaces/{tenant}/{namespace}?force=true while pulsar.broker.forceDeleteNamespaceAllowed=false on the target broker. The check runs after tenant DELETE_NAMESPACE authorization and policies read-only validation, before any topics are inspected.

Common situations: Operators scripting namespace teardown with force=true on a default-configured broker; cluster-to-cluster config drift where dev brokers allow force delete but prod does not; upgrading Pulsar where the guard default was changed/adopted.

Related errors


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