apache/pulsar · error · RestException
RestException(e)
Error message
RestException(e)
What it means
A generic RestException wrapping an underlying exception thrown while force-deleting all namespaces under a tenant in internalDeleteTenantAsyncForcefully. The broker failed to delete one or more namespaces (force delete), so the tenant deletion is aborted and the HTTP response carries the wrapped cause (often 500 or the cause's status).
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TenantsBase.java:288
protected CompletableFuture<Void> internalDeleteTenantAsyncForcefully(String tenant) {
if (!pulsar().getConfiguration().isForceDeleteTenantAllowed()) {
return FutureUtil.failedFuture(
new RestException(Status.METHOD_NOT_ALLOWED, "Broker doesn't allow forced deletion of tenants"));
}
return tenantResources().getListOfNamespacesAsync(tenant)
.thenApply(namespaces -> {
final List<CompletableFuture<Void>> futures = new ArrayList<>();
try {
PulsarAdmin adminClient = pulsar().getAdminClient();
for (String namespace : namespaces) {
futures.add(adminClient.namespaces().deleteNamespaceAsync(namespace, true));
}
} catch (Exception e) {
log.error()
.attr("namespaces", namespaces)
.exception(e)
.log("Failed to force delete namespaces");
throw new RestException(e);
}
return futures;
})
.thenCompose(futures -> FutureUtil.waitForAll(futures))
.thenCompose(__ -> internalDeleteTenantAsync(tenant));
}
private CompletableFuture<Void> validateClustersAsync(TenantInfo info) {
if (info == null) {
return FutureUtil.failedFuture(new RestException(Status.PRECONDITION_FAILED, "TenantInfo is null"));
}
Set<String> allowedClusters = info.getAllowedClusters();
if (allowedClusters == null) {
return FutureUtil.failedFuture(new RestException(Status.PRECONDITION_FAILED, "Clusters cannot be null"));
}
Set<String> cleanedClusters = allowedClusters.stream()View on GitHub (pinned to 820761864e)
Solutions
- Inspect the broker log entry 'Failed to force delete namespaces' for the wrapped cause and the namespaces list; fix the underlying namespace deletion error first.
- Delete the failing namespaces individually via DELETE /admin/v2/namespaces/{ns} to see the precise per-namespace error.
- Check broker health/ownership: ensure all brokers hosting the tenant's namespace bundles are up, or unload the bundles before deleting.
- Verify metadata store connectivity and retry the tenant force-delete after transient errors.
- As a last resort remove leftover namespace metadata, then retry tenant deletion (manual metadata cleanup requires care).
Example fix
// before
admin.tenants().deleteTenant(tenant, true); // fails with opaque RestException
// after
// delete namespaces first with error visibility
for (String ns : admin.namespaces().getNamespaces(tenant)) {
admin.namespaces().deleteNamespace(ns, true); // surfaces per-namespace failure
}
admin.tenants().deleteTenant(tenant, true); Defensive patterns
Strategy: try-catch
Validate before calling
// Check tenant exists and namespaces are deletable before force delete
List<String> ns = admin.namespaces().getNamespaces(tenant);
for (String n : ns) {
admin.namespaces().getBundles(n); // throws if namespace is in a bad state
} Try / catch
try {
admin.tenants().deleteTenant(tenant, true);
} catch (PulsarAdminException e) {
// inspect broker log 'Failed to force delete namespaces'; retry per-namespace
for (String n : admin.namespaces().getNamespaces(tenant)) {
try { admin.namespaces().deleteNamespace(n, true); }
catch (PulsarAdminException nsEx) { log.error("ns {} failed: {}", n, nsEx.getMessage()); }
}
} Prevention
- Delete namespaces explicitly before deleting the tenant so failures are attributable.
- Ensure brokers owning the tenant's bundles are healthy before deletion.
- Retry transient metadata-store errors with backoff.
- Check the broker log attr 'namespaces' to identify the offending namespace.
When it happens
Trigger: DELETE /admin/v2/tenants/{tenant} (with force=true) when async deletion of the tenant's namespaces fails — e.g. a namespace is still being used, broker ownership teardown fails, metadata store errors, or a namespace delete returns an error.
Common situations: Force-deleting a tenant with many/stuck namespaces; namespaces owned by brokers that are unreachable; ZooKeeper/metadata store connectivity problems; policies or topics still holding the namespace busy; concurrent delete of the same tenant.
Related errors
- This Broker is not configured with transactionCoordinatorEna
- RestException(e.getCause())
- Cannot start the service once it was stopped
- webServicePort/webServicePortTls or http/https bindAddresses
- The retention size must > the backlog quota limit size, but
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/764f37cbbe9752fa.
Report an issue: GitHub.