{"record":{"id":"16bd3e76b7d2af30","repo":"apache/pulsar","slug":"topic-s-not-found","errorCode":null,"errorMessage":"Topic %s not found.","messagePattern":"Topic (.+?) not found\\.","errorType":"http","errorClass":"RestException","httpStatus":404,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java","lineNumber":835,"sourceCode":"\n    protected void internalDeletePartitionedTopic(AsyncResponse asyncResponse,\n                                                  boolean authoritative,\n                                                  boolean force) {\n        validateNamespaceOperationAsync(topicName.getNamespaceObject(), NamespaceOperation.DELETE_TOPIC)\n                .thenCompose(__ -> validateTopicOwnershipAsync(topicName, authoritative))\n                .thenCompose(__ -> pulsar().getBrokerService()\n                        .fetchPartitionedTopicMetadataAsync(topicName)\n                        .thenCompose(partitionedMeta -> {\n                            final int numPartitions = partitionedMeta.partitions;\n                            if (numPartitions < 1) {\n                                return pulsar().getNamespaceService().checkNonPartitionedTopicExists(topicName)\n                                        .thenApply(exists -> {\n                                    if (exists) {\n                                        throw new RestException(Response.Status.CONFLICT,\n                                                String.format(\"%s is a non-partitioned topic. Instead of calling\"\n                                                        + \" delete-partitioned-topic please call delete.\", topicName));\n                                    } else {\n                                        throw new RestException(Status.NOT_FOUND,\n                                                String.format(\"Topic %s not found.\", topicName));\n                                    }\n                                });\n                            }\n                            return internalRemovePartitionsAuthenticationPoliciesAsync()\n                                    .thenCompose(unused -> internalRemovePartitionsTopicAsync(numPartitions, force));\n                        })\n                // Only tries to delete the znode for partitioned topic when all its partitions are successfully deleted\n                ).thenCompose(ignore ->\n                        pulsar().getBrokerService().deleteSchema(topicName).exceptionally(ex -> null)\n                ).thenCompose(ignore ->\n                        pulsar().getTopicPoliciesService().deleteTopicPoliciesAsync(topicName).exceptionally(ex -> null)\n                ).thenCompose(__ -> getPulsarResources().getNamespaceResources().getPartitionedTopicResources()\n                        .runWithMarkDeleteAsync(topicName, () -> namespaceResources()\n                                .getPartitionedTopicResources().deletePartitionedTopicAsync(topicName)))\n                .thenAccept(__ -> {\n                    log.info()\n                            .attr(\"topic\", topicName)","sourceCodeStart":817,"sourceCodeEnd":853,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java#L817-L853","documentation":"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.'","triggerScenarios":"DELETE /admin/v2/persistent/{ns}/{topic}/partitionedTopic for a topic name with no partitioned metadata and no underlying topic anywhere in the cluster.","commonSituations":"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.","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."],"exampleFix":"// before\npulsar-admin topics delete-partitioned-topic my-tenant/my-ns/gone-topic   // 404\n// after (idempotent cleanup)\npulsar-admin topics list-partitioned-topics my-tenant/my-ns | grep gone-topic || echo \"already deleted\"","handlingStrategy":"try-catch","validationCode":"try {\n    admin.topics().getPartitionedTopicMetadata(topic);\n} catch (PulsarAdminException.NotFoundException e) {\n    return; // nothing to delete\n}\nadmin.topics().deletePartitionedTopic(topic);","typeGuard":null,"tryCatchPattern":"try {\n    admin.topics().deletePartitionedTopic(topic);\n} catch (PulsarAdminException.NotFoundException e) {\n    // already deleted; treat as success in idempotent cleanup\n}","preventionTips":["Make cleanup scripts idempotent (404 = success)","Verify topic existence before delete operations","Target the cluster where the topic was created"],"tags":["pulsar","rest-api","topic-not-found"],"backgroundTag":"topic-not-found","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"}