{"record":{"id":"9ced449ae2acb30d","repo":"apache/pulsar","slug":"cannot-delete-non-empty-namespace","errorCode":null,"errorMessage":"Cannot delete non empty namespace","messagePattern":"Cannot delete non empty namespace","errorType":"http","errorClass":"RestException","httpStatus":409,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java","lineNumber":343,"sourceCode":"                                            allSystemTopics.add(topic);\n                                        }\n                                    }\n                                }\n                                for (String topic : allPartitionedTopics) {\n                                    if (!pulsar().getBrokerService().isSystemTopic(TopicName.get(topic))) {\n                                        hasNonSystemTopic = true;\n                                        allUserCreatedPartitionTopics.add(topic);\n                                    } else {\n                                        if (SystemTopicNames.isTopicPoliciesSystemTopic(topic)) {\n                                            partitionedTopicPolicy.add(topic);\n                                        } else {\n                                            allPartitionedSystemTopics.add(topic);\n                                        }\n                                    }\n                                }\n                                if (!force) {\n                                    if (hasNonSystemTopic) {\n                                        throw new RestException(Status.CONFLICT, \"Cannot delete non empty namespace\");\n                                    }\n                                }\n                                final CompletableFuture<Void> markDeleteFuture;\n                                if (policies != null && policies.deleted) {\n                                    markDeleteFuture = CompletableFuture.completedFuture(null);\n                                } else {\n                                    markDeleteFuture = namespaceResources().setPoliciesAsync(namespaceName, old -> {\n                                        old.deleted = true;\n                                        return old;\n                                    });\n                                }\n                                return markDeleteFuture.thenCompose(__ ->\n                                                internalDeleteTopicsAsync(allUserCreatedTopics))\n                                        .thenCompose(ignore ->\n                                                internalDeletePartitionedTopicsAsync(allUserCreatedPartitionTopics))\n                                        .thenCompose(ignore ->\n                                                internalDeleteTopicsAsync(allSystemTopics))\n                                        .thenCompose(ignore ->","sourceCodeStart":325,"sourceCodeEnd":361,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java#L325-L361","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ncurl -X DELETE http://broker:8080/admin/v2/namespaces/my-tenant/my-ns\n// 409 Cannot delete non empty namespace\n\n// after\ncurl -X DELETE http://broker:8080/admin/v2/namespaces/my-tenant/my-ns/topics\n# delete each topic, then:\ncurl -X DELETE http://broker:8080/admin/v2/namespaces/my-tenant/my-ns","handlingStrategy":"validation","validationCode":"const topics = await admin.namespaces().getTopics ? null : null;\nconst all = [\n  ...(await admin.namespaces().getPersistentTopics(tenant, ns)),\n  ...(await admin.namespaces().getNonPersistentTopics ? [] : [])\n];\nconst userTopics = all.filter(t => !t.includes('__transaction') && !t.includes('_change_events'));\nif (userTopics.length > 0) throw new Error(`namespace ${ns} still has ${userTopics.length} topics`);","typeGuard":null,"tryCatchPattern":"try {\n  await admin.namespaces().deleteNamespace(tenant, ns);\n} catch (e) {\n  if (e instanceof PulsarAdminException && e.getStatusCode() === 409) {\n    // drain topics then retry\n  } else throw e;\n}","preventionTips":["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"],"tags":["pulsar","rest-api","namespace-deletion","conflict"],"backgroundTag":"namespace-not-empty","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"}