{"record":{"id":"4a2675bf01b3f19c","repo":"apache/pulsar","slug":"message-not-found","errorCode":null,"errorMessage":"Message not found","messagePattern":"Message not found","errorType":"http","errorClass":"RestException","httpStatus":404,"severity":"info","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java","lineNumber":3110,"sourceCode":"                        \"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) {\n                throw new RestException(Status.NOT_FOUND, \"Message not found\");\n            } catch (Exception exception) {\n                log.error()\n                        .attr(\"position\", messagePosition)\n                        .attr(\"topic\", topicName)\n                        .attr(\"subscription\", subName)\n                        .exception(exception)\n                        .log(\"Failed to peek message\");\n                throw new RestException(exception);\n            } finally {\n                if (entry != null) {\n                    entry.release();\n                }\n            }\n        });\n    }\n\n    protected CompletableFuture<Response> internalExamineMessageAsync(String initialPosition, long messagePosition,\n                                                                      boolean authoritative) {","sourceCodeStart":3092,"sourceCodeEnd":3128,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java#L3092-L3128","documentation":"When generating the HTTP response for a peeked entry, the broker catches a NullPointerException thrown while constructing the response (e.g. the entry payload/metadata was null or already released) and converts it into a 404 NOT_FOUND RestException with message 'Message not found'. It signals that although a peek was attempted, no retrievable message exists at the requested position.","triggerScenarios":"generateResponseWithEntry(null/invalid entry) inside the peek path; concurrent cursor advancement or retention deleting the entry between lookup and response generation; requesting a position beyond the retained range.","commonSituations":"Peeking with a large position on a topic with fewer entries; message expiry/compaction removing the entry mid-request; race between a consumer ack and an admin peek.","solutions":["Retry the peek; transient races often clear on the next attempt","Validate the position is within the topic's retained entry range (getNumberOfEntries / stats) before peeking","Check message TTL and retention policies if entries disappear quickly"],"exampleFix":"// before\nResponse r = admin.topics().peekNthMessage(topic, \"sub\", 1_000_000);\n// after\nlong total = admin.topics().getStats(topic).getNumberOfEntries();\nif (position < total) { Response r = admin.topics().peekNthMessage(topic, \"sub\", (int) position); }","handlingStrategy":"retry","validationCode":"// check position is within retained range\nTopicStats stats = admin.topics().getStats(topic);\nif (position >= stats.getNumberOfEntries()) throw new IllegalArgumentException(\"position out of range\");","typeGuard":null,"tryCatchPattern":"try { admin.topics().peekNthMessage(topic, sub, position); }\ncatch (PulsarAdminException e) {\n    if (e.getStatusCode() == 404) { /* message gone: rescan or skip */ }\n}","preventionTips":["Validate position against current entry count","Watch TTL/retention settings that delete entries concurrently"],"tags":["rest-api","message-not-found","not-found","race-condition","admin"],"backgroundTag":"message-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"}