{"record":{"id":"8cd58cd134710922","repo":"apache/pulsar","slug":"expire-message-by-position-is-not-supported-for-no","errorCode":null,"errorMessage":"Expire message by position is not supported for non-persistent topic.","messagePattern":"Expire message by position is not supported for non-persistent topic\\.","errorType":"exception","errorClass":"java.lang.UnsupportedOperationException","httpStatus":null,"severity":"warning","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/service/nonpersistent/NonPersistentSubscription.java","lineNumber":510,"sourceCode":"            return Collections.emptyList();\n        }\n    }\n\n    @Override\n    public boolean expireMessages(int messageTTLInSeconds) {\n        throw new UnsupportedOperationException(\"Expire message by timestamp is not supported for\"\n                + \" non-persistent topic.\");\n    }\n\n    @Override\n    public CompletableFuture<Boolean> expireMessagesAsync(int messageTTLInSeconds) {\n        return CompletableFuture.failedFuture(new UnsupportedOperationException(\"Expire message by timestamp is not\"\n                + \" supported for non-persistent topic.\"));\n    }\n\n    @Override\n    public boolean expireMessages(Position position) {\n        throw new UnsupportedOperationException(\"Expire message by position is not supported for\"\n                + \" non-persistent topic.\");\n    }\n\n    public NonPersistentSubscriptionStatsImpl getStats(GetStatsOptions getStatsOptions) {\n        NonPersistentSubscriptionStatsImpl subStats = new NonPersistentSubscriptionStatsImpl();\n        subStats.bytesOutCounter = bytesOutFromRemovedConsumers.longValue();\n        subStats.msgOutCounter = msgOutFromRemovedConsumer.longValue();\n\n        NonPersistentDispatcher dispatcher = this.dispatcher;\n        if (dispatcher != null) {\n            dispatcher.getConsumers().forEach(consumer -> {\n                ConsumerStatsImpl consumerStats = consumer.getStats();\n                if (!getStatsOptions.isExcludeConsumers()) {\n                    subStats.consumers.add(consumerStats);\n                }\n                subStats.msgRateOut += consumerStats.msgRateOut;\n                subStats.messageAckRate += consumerStats.messageAckRate;\n                subStats.msgThroughputOut += consumerStats.msgThroughputOut;","sourceCodeStart":492,"sourceCodeEnd":528,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/nonpersistent/NonPersistentSubscription.java#L492-L528","documentation":"NonPersistentSubscription.expireMessages(Position position) unconditionally throws UnsupportedOperationException — expiring messages up to a specific position (cumulative expiry) is not meaningful for non-persistent topics since messages are not retained in storage.","triggerScenarios":"Calling subscription.expireMessages(Position) or admin REST/CLI 'expire messages up to position' against a subscription on a non-persistent topic.","commonSituations":"Admin console/API expire-messages-by-position invoked on non-persistent topic; automation scripts applying position-based expiry uniformly across topics.","solutions":["Restrict position-based expiry calls to persistent topics","Check topic type via admin API (persistent topic namespace) before issuing expire-messages","Handle the UnsupportedOperationException (or its async failed-future equivalent) in admin tooling","Use disconnect-consumer or clear-backlog operations instead for non-persistent subscriptions"],"exampleFix":"// before\nadmin.topics().expireMessages(topic, subName, position);\n// after\nif (topic.startsWith(\"persistent://\")) {\n    admin.topics().expireMessages(topic, subName, position);\n}","handlingStrategy":"type-guard","validationCode":"if (!topicName.getPersistent()) {\n    return; // skip position-based expiry\n}\nadmin.topics().expireMessages(topic, subName, position);","typeGuard":"boolean supportsPositionExpiry(String topic) {\n    return topic.startsWith(\"persistent://\");\n}","tryCatchPattern":"try {\n    subscription.expireMessages(position);\n} catch (UnsupportedOperationException e) {\n    log.debug(\"Position-based expiry unsupported for non-persistent topic\");\n}","preventionTips":["Gate position-based expiry tooling on persistent:// scheme","Train ops on non-persistent topic limitations (no backlog/retention semantics)","Use clear-backlog or disconnect instead for non-persistent subscriptions"],"tags":["java","broker","non-persistent","ttl","unsupported-operation"],"backgroundTag":"operation-not-supported-on-non-persistent-topic","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"}