apache/pulsar · error · RestException
Cannot delete non empty namespace
Error message
Cannot delete non empty namespace
What it means
This is a 409 CONFLICT thrown by the broker's namespace deletion flow when a namespace still contains non-system topics and the delete was not requested with force=true. The broker protects against accidental data loss: it inventories all topics (including partitioned and system topics) in the namespace and refuses to delete the namespace while regular user topics remain. System topics are exempt, but any non-system topic causes the abort.
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java:343
allSystemTopics.add(topic);
}
}
}
for (String topic : allPartitionedTopics) {
if (!pulsar().getBrokerService().isSystemTopic(TopicName.get(topic))) {
hasNonSystemTopic = true;
allUserCreatedPartitionTopics.add(topic);
} else {
if (SystemTopicNames.isTopicPoliciesSystemTopic(topic)) {
partitionedTopicPolicy.add(topic);
} else {
allPartitionedSystemTopics.add(topic);
}
}
}
if (!force) {
if (hasNonSystemTopic) {
throw new RestException(Status.CONFLICT, "Cannot delete non empty namespace");
}
}
final CompletableFuture<Void> markDeleteFuture;
if (policies != null && policies.deleted) {
markDeleteFuture = CompletableFuture.completedFuture(null);
} else {
markDeleteFuture = namespaceResources().setPoliciesAsync(namespaceName, old -> {
old.deleted = true;
return old;
});
}
return markDeleteFuture.thenCompose(__ ->
internalDeleteTopicsAsync(allUserCreatedTopics))
.thenCompose(ignore ->
internalDeletePartitionedTopicsAsync(allUserCreatedPartitionTopics))
.thenCompose(ignore ->
internalDeleteTopicsAsync(allSystemTopics))
.thenCompose(ignore ->View on GitHub (pinned to 820761864e)
Solutions
- List and delete all topics in the namespace first: GET /admin/v2/namespaces/{tenant}/{namespace}/topics then DELETE each (use persistent/non-persistent and partitioned endpoints).
- Retry the namespace delete with force=true, which requires the broker config isForceDeleteNamespaceAllowed=true (see error 91).
- Check for auto-topic-creation being enabled on the namespace and disable it so topics are not recreated between listing and deletion.
- Verify no lingering system/non-partitioned topic leftovers by re-listing topics after deletion before retrying.
Example fix
// before curl -X DELETE http://broker:8080/admin/v2/namespaces/my-tenant/my-ns // 409 Cannot delete non empty namespace // after curl -X DELETE http://broker:8080/admin/v2/namespaces/my-tenant/my-ns/topics # delete each topic, then: curl -X DELETE http://broker:8080/admin/v2/namespaces/my-tenant/my-ns
Defensive patterns
Strategy: validation
Validate before calling
const topics = await admin.namespaces().getTopics ? null : null;
const all = [
...(await admin.namespaces().getPersistentTopics(tenant, ns)),
...(await admin.namespaces().getNonPersistentTopics ? [] : [])
];
const userTopics = all.filter(t => !t.includes('__transaction') && !t.includes('_change_events'));
if (userTopics.length > 0) throw new Error(`namespace ${ns} still has ${userTopics.length} topics`); Try / catch
try {
await admin.namespaces().deleteNamespace(tenant, ns);
} catch (e) {
if (e instanceof PulsarAdminException && e.getStatusCode() === 409) {
// drain topics then retry
} else throw e;
} Prevention
- Delete all topics before deleting the namespace
- Treat 409 as 'drain first' signal, not a bug
- Beware auto-topic-creation recreating topics mid-teardown
- Use force=true only with forceDeleteNamespaceAllowed enabled
When it happens
Trigger: Calling DELETE /admin/v2/namespaces/{tenant}/{namespace} (NamespacesBase.internalDeleteNamespaceAsync -> internalRetryableDeleteNamespaceAsync0) while the namespace still has non-system topics, with force=false (the default). Also occurs when force delete is retried but topic deletion has not fully propagated yet.
Common situations: Developers tearing down tenants in CI and forgetting to delete topics first; lingering topics from producers/consumers that auto-created topics; partitioned topics whose partitions were deleted but metadata remains; testing force-delete locally without realizing isForceDeleteNamespaceAllowed=false on the broker.
Related errors
- %s is a non-partitioned topic. Instead of calling delete-par
- cluster data is required
- Cluster already exists
- ${duplicateBrokers} already exists in ${domainName}
- Broker doesn't allow forced deletion of namespaces
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/9ced449ae2acb30d.
Report an issue: GitHub.