{"record":{"id":"d94eaae9abd49f77","repo":"apache/pulsar","slug":"topic-does-not-exist","errorCode":null,"errorMessage":"Topic does not exist","messagePattern":"Topic does not exist","errorType":"http","errorClass":"RestException","httpStatus":404,"severity":"warning","filePath":"pulsar-websocket/src/main/java/org/apache/pulsar/websocket/admin/WebSocketProxyStatsBase.java","lineNumber":51,"sourceCode":"@CustomLog\npublic class WebSocketProxyStatsBase extends WebSocketWebResource {\n\n    protected Collection<Metrics> internalGetMetrics() throws Exception {\n        // Ensure super user access only\n        validateSuperUserAccess();\n        try {\n            return service().getProxyStats().getMetrics();\n        } catch (Exception e) {\n            log.error().attr(\"clientAppId\", clientAppId()).exception(e).log(\"Failed to generate metrics\");\n            throw new RestException(e);\n        }\n    }\n\n    protected ProxyTopicStat internalGetStats(TopicName topicName) {\n        validateUserAccess(topicName);\n        ProxyTopicStat stats = getStat(topicName);\n        if (stats == null) {\n            throw new RestException(Status.NOT_FOUND, \"Topic does not exist\");\n        }\n        return stats;\n    }\n\n    protected Map<String, ProxyTopicStat> internalGetProxyStats() {\n        validateSuperUserAccess();\n        return getStat();\n    }\n\n    private ProxyTopicStat getStat(TopicName topicName) {\n        String topicNameStr = topicName.toString();\n        if (!service().getProducers().containsKey(topicNameStr) && !service().getConsumers().containsKey(topicNameStr)\n                && !service().getReaders().containsKey(topicNameStr)) {\n            log.warn().attr(\"exist\", topicNameStr).log(\"topic doesn't exist\");\n            throw new RestException(Status.NOT_FOUND, \"Topic does not exist\");\n        }\n        ProxyTopicStat topicStat = new ProxyTopicStat();\n        if (service().getProducers().containsKey(topicNameStr)) {","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/admin/WebSocketProxyStatsBase.java#L33-L69","documentation":"internalGetStats validates access then looks up the in-memory ProxyTopicStat for the given topic name. If no stats object exists the topic has no active proxy handlers, so it returns HTTP 404 with 'Topic does not exist' via RestException. This is a lookup miss on the proxy's live handler registry, not a broker-side topic check.","triggerScenarios":"GET /admin/v2/websocket/.../stats/<topic> where the topic has no currently open WebSocket producers, consumers, or readers in this proxy instance (getStat(topicName) returned null).","commonSituations":"Querying stats after the client disconnected; querying the wrong topic name/tenant/namespace; hitting a different proxy instance than the one holding the connection (no shared stats store); typo in the topic path.","solutions":["Open a WebSocket producer/consumer/reader on the topic before requesting its proxy stats","Verify the exact topic name (tenant/namespace/topic) and that you are querying the proxy instance that holds the connection","Handle HTTP 404 from the stats endpoint gracefully — treat it as 'no active proxy sessions' rather than a hard failure","Aggregate stats across proxy instances via broker-level topic stats if the connection may live on another node"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// client-side: only request stats when a connection is known active\nif (!activeConnections.containsKey(topicName)) { throw new IllegalStateException(\"no active proxy session for \" + topicName); }","typeGuard":null,"tryCatchPattern":"Response r = target.path(topicName + \"/stats\").get(); if (r.getStatus() == 404) { return Optional.empty(); } return Optional.of(r.readEntity(ProxyTopicStat.class));","preventionTips":["Poll stats only while the WebSocket session is open","Treat 404 on proxy stats as 'no live sessions', not an error","Target the proxy instance that owns the connection (sticky routing)","Double-check topic name spelling/tenant/namespace"],"tags":["rest","admin-api","not-found"],"backgroundTag":"resource-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"}