{"record":{"id":"4a1950137eee3b39","repo":"apache/pulsar","slug":"subscription-has-active-connected-consumers-4a1950","errorCode":null,"errorMessage":"Subscription has active connected consumers","messagePattern":"Subscription has active connected consumers","errorType":"http","errorClass":"RestException","httpStatus":412,"severity":"warning","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java","lineNumber":1721,"sourceCode":"                        try {\n                            adminClient = pulsar().getAdminClient();\n                        } catch (PulsarServerException e) {\n                            return CompletableFuture.failedFuture(e);\n                        }\n                        for (int i = 0; i < partitionMetadata.partitions; i++) {\n                            TopicName topicNamePartition = topicName.getPartition(i);\n                            futures.add(adminClient.topics()\n                                    .deleteSubscriptionAsync(topicNamePartition.toString(), subName, force));\n                        }\n\n                        return FutureUtil.waitForAll(futures).handle((result, exception) -> {\n                            if (exception != null) {\n                                Throwable t = exception.getCause();\n                                if (t instanceof NotFoundException) {\n                                    throw new RestException(Status.NOT_FOUND,\n                                            \"Subscription not found\");\n                                } else if (t instanceof PreconditionFailedException) {\n                                    throw new RestException(Status.PRECONDITION_FAILED,\n                                            \"Subscription has active connected consumers\");\n                                } else {\n                                    throw new RestException(t);\n                                }\n                            }\n                            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) {","sourceCodeStart":1703,"sourceCodeEnd":1739,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java#L1703-L1739","documentation":"HTTP 412 PRECONDITION_FAILED returned when deleting a subscription whose cursor still has active connected consumers. The per-partition delete throws PreconditionFailedException (broker refuses to remove a subscription in use) and the aggregated handler converts it to 'Subscription has active connected consumers'.","triggerScenarios":"DELETE .../subscription/{subName} (or force=false unsubscribe) while consumers are connected on that subscription; also via `pulsar-admin topics unsubscribe` with connected readers/consumers using shared/exclusive subscriptions.","commonSituations":"Ops tries to clean up a subscription during business hours with live consumers; shared-subscription consumers reconnecting between check and delete; consumers stuck due to network issues but still registered; batch jobs deleting stale subscriptions without checking consumer count first.","solutions":["Disconnect all consumers of the subscription, then retry the delete.","Use force delete (`DELETE .../subscription/{sub}?force=true` or `pulsar-admin topics unsubscribe --force`) after confirming the consumers should be evicted.","Identify connected consumers with `pulsar-admin topics stats <topic>` (look at the subscription's consumers list) and shut them down first.","Schedule subscription cleanup during maintenance windows when consumers are stopped."],"exampleFix":"// before\ncurl -X DELETE .../persistent/t/ns/topic/subscription/old-sub   // 412\n// after\ncurl -X DELETE .../persistent/t/ns/topic/subscription/old-sub?force=true","handlingStrategy":"retry","validationCode":"TopicStats stats = admin.topics().getStats(topic);\nboolean hasConsumers = stats.getSubscriptions().getOrDefault(subName,\n        new SubscriptionStats()).consumers.stream().findAny().isPresent();\nif (!hasConsumers) {\n    admin.topics().deleteSubscription(topic, subName);\n}","typeGuard":null,"tryCatchPattern":"try {\n    admin.topics().deleteSubscription(topic, subName);\n} catch (PulsarAdminException.PreconditionFailedException e) {\n    // consumers still connected: disconnect then retry, or use force=true\n}","preventionTips":["Verify consumer counts in topic stats before deleting subscriptions","Stop consumers during maintenance windows for cleanup","Use force delete only after confirming eviction is safe"],"tags":["pulsar","subscription","consumers","rest-api"],"backgroundTag":"subscription-has-active-consumers","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"}