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

  1. Verify the topic exists with `pulsar-admin topics list-partitioned-topics <namespace>` before deleting; treat 404 as success in idempotent cleanup scripts.
  2. Correct the topic/namespace name in the request.
  3. Ensure the request targets the cluster where the topic was created.
  4. 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

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


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