apache/pulsar · error · RestException
Topic %s not found.
Error message
Topic %s not found.
What it means
HTTP 404 thrown by internalDeletePartitionedTopic when the topic is not partitioned AND does not exist at all (checkNonPartitionedTopicExists returns false). It is the 'fully missing topic' branch of the same check that yields 409 for existing non-partitioned topics — here there is nothing to delete, so the broker returns 'Topic %s not found.'
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java:835
protected void internalDeletePartitionedTopic(AsyncResponse asyncResponse,
boolean authoritative,
boolean force) {
validateNamespaceOperationAsync(topicName.getNamespaceObject(), NamespaceOperation.DELETE_TOPIC)
.thenCompose(__ -> validateTopicOwnershipAsync(topicName, authoritative))
.thenCompose(__ -> pulsar().getBrokerService()
.fetchPartitionedTopicMetadataAsync(topicName)
.thenCompose(partitionedMeta -> {
final int numPartitions = partitionedMeta.partitions;
if (numPartitions < 1) {
return pulsar().getNamespaceService().checkNonPartitionedTopicExists(topicName)
.thenApply(exists -> {
if (exists) {
throw new RestException(Response.Status.CONFLICT,
String.format("%s is a non-partitioned topic. Instead of calling"
+ " delete-partitioned-topic please call delete.", topicName));
} else {
throw new RestException(Status.NOT_FOUND,
String.format("Topic %s not found.", topicName));
}
});
}
return internalRemovePartitionsAuthenticationPoliciesAsync()
.thenCompose(unused -> internalRemovePartitionsTopicAsync(numPartitions, force));
})
// Only tries to delete the znode for partitioned topic when all its partitions are successfully deleted
).thenCompose(ignore ->
pulsar().getBrokerService().deleteSchema(topicName).exceptionally(ex -> null)
).thenCompose(ignore ->
pulsar().getTopicPoliciesService().deleteTopicPoliciesAsync(topicName).exceptionally(ex -> null)
).thenCompose(__ -> getPulsarResources().getNamespaceResources().getPartitionedTopicResources()
.runWithMarkDeleteAsync(topicName, () -> namespaceResources()
.getPartitionedTopicResources().deletePartitionedTopicAsync(topicName)))
.thenAccept(__ -> {
log.info()
.attr("topic", topicName)View on GitHub (pinned to 820761864e)
Solutions
- Verify the topic exists with `pulsar-admin topics list-partitioned-topics <namespace>` before deleting; treat 404 as success in idempotent cleanup scripts.
- Correct the topic/namespace name in the request.
- Ensure the request targets the cluster where the topic was created.
- If it should be partitioned, recreate it first with create-partitioned-topic.
Example fix
// before pulsar-admin topics delete-partitioned-topic my-tenant/my-ns/gone-topic // 404 // after (idempotent cleanup) pulsar-admin topics list-partitioned-topics my-tenant/my-ns | grep gone-topic || echo "already deleted"
Defensive patterns
Strategy: try-catch
Validate before calling
try {
admin.topics().getPartitionedTopicMetadata(topic);
} catch (PulsarAdminException.NotFoundException e) {
return; // nothing to delete
}
admin.topics().deletePartitionedTopic(topic); Try / catch
try {
admin.topics().deletePartitionedTopic(topic);
} catch (PulsarAdminException.NotFoundException e) {
// already deleted; treat as success in idempotent cleanup
} Prevention
- Make cleanup scripts idempotent (404 = success)
- Verify topic existence before delete operations
- Target the cluster where the topic was created
When it happens
Trigger: DELETE /admin/v2/persistent/{ns}/{topic}/partitionedTopic for a topic name with no partitioned metadata and no underlying topic anywhere in the cluster.
Common situations: Deleting an already-deleted topic (double cleanup in scripts); typo in topic or namespace; operating against the wrong cluster; cleanup jobs racing with topic deletion by another admin.
Related errors
- Topic %s does not exist
- getTopicNotFoundErrorMessage(topicName.toString())
- cluster data is required
- Cannot delete non empty namespace
- Local cluster is not part of replicate cluster list
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/16bd3e76b7d2af30.
Report an issue: GitHub.