{"record":{"id":"e5e27f22e1aea583","repo":"apache/pulsar","slug":"peek-messages-on-a-non-persistent-topic-is-not-all","errorCode":null,"errorMessage":"Peek messages on a non-persistent topic is not allowed","messagePattern":"Peek messages on a non-persistent topic is not allowed","errorType":"http","errorClass":"RestException","httpStatus":405,"severity":"warning","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java","lineNumber":3091,"sourceCode":"                            if (topicMetadata.partitions > 0) {\n                                throw new RestException(Status.METHOD_NOT_ALLOWED,\n                                        \"Peek messages on a partitioned topic is not allowed\");\n                            }\n                            return CompletableFuture.completedFuture(null);\n                        });\n            } else {\n                return CompletableFuture.completedFuture(null);\n            }\n        }).thenCompose(__ -> validateTopicOwnershipAsync(topicName, authoritative))\n        .thenCompose(__ -> getTopicReferenceAsync(topicName))\n        .thenCompose(topic -> {\n            CompletableFuture<Entry> entry;\n            if (!(topic instanceof PersistentTopic)) {\n                log.error()\n                        .attr(\"topic\", topicName)\n                        .attr(\"subscription\", subName)\n                        .log(\"Not supported operation of non-persistent topic\");\n                throw new RestException(Status.METHOD_NOT_ALLOWED,\n                        \"Peek messages on a non-persistent topic is not allowed\");\n            } else {\n                if (subName.startsWith(((PersistentTopic) topic).getReplicatorPrefix())) {\n                    PersistentReplicator repl = getReplicatorReference(subName, (PersistentTopic) topic);\n                    entry = repl.peekNthMessage(messagePosition);\n                } else {\n                    entry = findOrCreateSubscriptionAsync(subName, (PersistentTopic) topic)\n                            .thenCompose(sub -> sub.peekNthMessage(messagePosition));\n                }\n            }\n            return entry.thenApply(e -> Pair.of(e, (PersistentTopic) topic));\n        }).thenCompose(entryTopicPair -> {\n            Entry entry = entryTopicPair.getLeft();\n            PersistentTopic persistentTopic = entryTopicPair.getRight();\n            try {\n                Response response = generateResponseWithEntry(entry, persistentTopic);\n                return CompletableFuture.completedFuture(response);\n            } catch (NullPointerException npe) {","sourceCodeStart":3073,"sourceCodeEnd":3109,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java#L3073-L3109","documentation":"Peeking messages requires a PersistentTopic; non-persistent topics do not store entries in a durable ledger that can be read by position. After ownership, if the topic reference fails the instanceof PersistentTopic check the broker throws 405 METHOD_NOT_ALLOWED 'Peek messages on a non-persistent topic is not allowed'.","triggerScenarios":"Calling the peek/preview REST endpoint (peekNthMessage path) with a topic that resolves to a non-persistent topic reference.","commonSituations":"Pointing debug tooling at topics in the non-persistent:// domain; clusters where the same namespace mixes persistent and non-persistent topics and scripts assume persistent.","solutions":["Only peek on persistent topics","Verify the topic domain prefix before invoking peek","For non-persistent topics, use an active consumer with the reader/producer API to observe messages in-flight"],"exampleFix":"// before\nMessages m = admin.topics().peekMessages(\"non-persistent://public/default/my-topic\", \"sub\", 1);\n// after\nMessages m = admin.topics().peekMessages(\"persistent://public/default/my-topic\", \"sub\", 1);","handlingStrategy":"validation","validationCode":"if (!topic.startsWith(\"persistent://\")) {\n    throw new IllegalArgumentException(\"Peek requires a persistent topic\");\n}","typeGuard":"boolean isPersistentTopic(String topic) { return topic.startsWith(\"persistent://\"); }","tryCatchPattern":null,"preventionTips":["Filter namespace topic listings by domain before peeping","Never assume a topic is persistent based on name alone"],"tags":["rest-api","non-persistent-topic","method-not-allowed","admin"],"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-14T00:17:10.932Z"}