{"record":{"id":"7bf854c9762b93e6","repo":"apache/pulsar","slug":"getsubnotfounderrormessage-topicname-tostring-s","errorCode":null,"errorMessage":"getSubNotFoundErrorMessage(topicName.toString(), subName)","messagePattern":"getSubNotFoundErrorMessage\\(topicName\\.toString\\(\\), subName\\)","errorType":"http","errorClass":"RestException","httpStatus":404,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java","lineNumber":1745,"sourceCode":"                            return null;\n                        });\n                    }\n                    return internalDeleteSubscriptionForNonPartitionedTopicAsync(subName, authoritative, force);\n                });\n            }\n        });\n    }\n\n    // Note: this method expects the caller to check authorization\n    private CompletableFuture<Void> internalDeleteSubscriptionForNonPartitionedTopicAsync(String subName,\n                                                                                          boolean authoritative,\n                                                                                          boolean force) {\n        return validateTopicOwnershipAsync(topicName, authoritative)\n                .thenCompose(__ -> getTopicReferenceAsync(topicName))\n                .thenCompose((topic) -> {\n                    Subscription sub = topic.getSubscription(subName);\n                    if (sub == null) {\n                        throw new RestException(Status.NOT_FOUND,\n                                getSubNotFoundErrorMessage(topicName.toString(), subName));\n                    }\n                    return force ? sub.deleteForcefully() : sub.delete();\n                });\n    }\n\n    private void internalAnalyzeSubscriptionBacklogForNonPartitionedTopic(AsyncResponse asyncResponse,\n                                                                          String subName,\n                                                                          Optional<Position> position,\n                                                                          boolean authoritative) {\n        validateTopicOwnershipAsync(topicName, authoritative)\n                .thenCompose(__ -> validateTopicOperationAsync(topicName, TopicOperation.CONSUME, subName))\n                .thenCompose(__ -> getTopicReferenceAsync(topicName))\n                .thenCompose(topic -> {\n                            Subscription sub = topic.getSubscription(subName);\n                            if (sub == null) {\n                                throw new RestException(Status.NOT_FOUND,\n                                        getSubNotFoundErrorMessage(topicName.toString(), subName));","sourceCodeStart":1727,"sourceCodeEnd":1763,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java#L1727-L1763","documentation":"HTTP 404 thrown when performing a subscription operation (delete, or the deleteSubscriptionAsync path shown) on a specific topic where topic.getSubscription(subName) returns null — the topic exists but that particular subscription does not. Unlike the partitioned aggregation path, this check is per topic reference, using the standard sub-not-found message with topic and subscription names.","triggerScenarios":"DELETE /admin/v2/persistent/{ns}/{topic}/subscription/{subName} (force or normal) where the subscription cursor was never created or was already removed on that topic/partition.","commonSituations":"Typo in subscription name; unsubscribe racing with the subscription's auto-deletion after consumers left; operating on a partition that never had the subscription while others did; double-invocation of cleanup tooling.","solutions":["List subscriptions with `pulsar-admin topics subscriptions <topic>` and fix the name.","Handle 404 as success in idempotent deletion logic.","If per-partition state diverged on a partitioned topic, run the delete against the partitioned parent so all partitions converge.","Check subscription expiration / auto-delete config that may have removed the subscription."],"exampleFix":"// before\nadmin.topics().deleteSubscription(\"persistent://t/ns/topic-partition-0\", \"subb\"); // 404 typo\n// after\nadmin.topics().subscriptions(\"persistent://t/ns/topic-partition-0\").forEach(s -> {\n    if (\"mysub\".equals(s)) admin.topics().deleteSubscription(\"persistent://t/ns/topic-partition-0\", s);\n});","handlingStrategy":"try-catch","validationCode":"if (!admin.topics().getSubscriptions(topic).contains(subName)) {\n    return; // subscription absent\n}\nadmin.topics().deleteSubscription(topic, subName);","typeGuard":null,"tryCatchPattern":"try {\n    admin.topics().deleteSubscription(topic, subName);\n} catch (PulsarAdminException.NotFoundException e) {\n    // no such subscription; idempotent success\n}","preventionTips":["Confirm subscription names via topics subscriptions command","Avoid double-invoked cleanup without existence checks","Operate on the partitioned parent rather than individual partitions to keep state consistent"],"tags":["pulsar","subscription","rest-api"],"backgroundTag":"subscription-not-found","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}