{"record":{"id":"2e6910d1c415c30f","repo":"apache/pulsar","slug":"failed-due-to-heap-memory-limit-exceeded","errorCode":null,"errorMessage":"Failed due to heap memory limit exceeded","messagePattern":"Failed due to heap memory limit exceeded","errorType":"http","errorClass":"CompletionException","httpStatus":429,"severity":"warning","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java","lineNumber":216,"sourceCode":"                    // for failed request\n                    // handle resetting the TopicListSizeResultCache.ResultHolder\n                    listSizeHolder.resetIfInitializing();\n                    // cancel any pending permit request\n                    permitRequestCancelled.set(true);\n                }\n                AsyncDualMemoryLimiter.AsyncDualMemoryLimiterPermit initialPermit = initialPermitsRef.get();\n                if (initialPermit != null) {\n                    maxTopicListInFlightLimiter.release(initialPermit);\n                }\n                AsyncDualMemoryLimiter.AsyncDualMemoryLimiterPermit permits = permitsRef.get();\n                if (permits != null) {\n                    maxTopicListInFlightLimiter.release(permits);\n                }\n            }\n        });\n        return listSizeHolder.getSizeAsync().thenCompose(initialSize -> maxTopicListInFlightLimiter.acquire(initialSize,\n                AsyncDualMemoryLimiter.LimitType.HEAP_MEMORY, isPermitRequestCancelled).exceptionally(t -> {\n            throw new CompletionException(\n                    new RestException(Status.TOO_MANY_REQUESTS, \"Failed due to heap memory limit exceeded\"));\n        }).thenCompose(initialPermits -> {\n            initialPermitsRef.set(initialPermits);\n            // perform the actual get list of topics operation\n            return doInternalGetListOfTopics(policies, mode).thenCompose(topicList -> {\n                long actualSize = TopicListMemoryLimiter.estimateTopicListSize(topicList);\n                listSizeHolder.updateSize(actualSize);\n                return maxTopicListInFlightLimiter.update(initialPermits, actualSize, isPermitRequestCancelled)\n                        .exceptionally(t -> {\n                            throw new CompletionException(new RestException(Status.TOO_MANY_REQUESTS,\n                                    \"Failed due to heap memory limit exceeded\"));\n                        }).thenApply(permits -> {\n                            permitsRef.set(permits);\n                            initialPermitsRef.set(null);\n                            return topicList;\n                        });\n            });\n        }));","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java#L198-L234","documentation":"A 429 TOO_MANY_REQUESTS thrown when the initial acquisition of in-flight memory permits for a namespace topic-list operation fails the broker's heap memory limit (AsyncDualMemoryLimiter with LimitType.HEAP_MEMORY). The broker bounds total memory used by concurrent topic-list responses; when the estimated list size would exceed the in-flight heap budget, it rejects the request instead of risking OOM.","triggerScenarios":"GET /admin/v3/namespaces/{tenant}/{ns}/topics (or ?mode=all/persistent/non-persistent) on a namespace with a very large number of topics while the broker's topic-list in-flight memory budget is already (nearly) exhausted by concurrent list requests.","commonSituations":"Huge namespaces (tens of thousands of topics) whose list results exceed the limiter's heap threshold; monitoring/automation polling many namespaces' topic lists concurrently; undersized broker heap making the budget small.","solutions":["Reduce the number of concurrent topic-list requests against the broker (add client-side rate limiting/serialization).","Use pagination/filtering where available (e.g. getTopics with mode filters) or narrower namespace partitioning to shrink result size.","Increase broker heap (-Xmx) and/or the max topic-list in-flight memory limiter configuration to raise the budget.","Retry the request after backing off — the limiter is in-flight based, so as other requests complete, permits free up."],"exampleFix":"// before: unbounded parallel listing\nnamespaces.forEach(ns -> admin.namespaces().getNamespaces(ns));\n// after: bounded concurrency + retry on 429\nExecutorService pool = Executors.newFixedThreadPool(2);\n// on RestException 429: back off and retry with exponential delay","handlingStrategy":"retry","validationCode":"// client-side: avoid listing very large namespaces concurrently\nif (knownTopicCount(ns) > LARGE_NS_THRESHOLD) { /* use pagination / serialize */ }","typeGuard":null,"tryCatchPattern":"try { admin.namespaces().getNamespaces(tenant + \"/\" + ns); }\ncatch (PulsarAdminException e) {\n  if (e.getStatusCode() == 429) { /* back off and retry, or reduce parallelism */ }\n  else throw e;\n}","preventionTips":["Limit concurrent topic-list calls (client-side semaphore)","Keep namespaces below the size that fits the broker's list memory budget","Right-size broker heap for topic-list workloads","Back off exponentially on 429 instead of hammering"],"tags":["rate-limit","memory","rest-api","topics"],"backgroundTag":"heap-memory-limit-exceeded","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"}