{"record":{"id":"7bb537cae997f557","repo":"apache/pulsar","slug":"failed-to-initialize-controller-for-topic","errorCode":null,"errorMessage":"Failed to initialize controller for ${topic}","messagePattern":"Failed to initialize controller for (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/service/scalable/ScalableTopicService.java","lineNumber":111,"sourceCode":"\n    // --- Controller management ---\n\n    /**\n     * Get or create a controller for a scalable topic. The controller will attempt\n     * leader election; only the leader actively coordinates consumers.\n     */\n    public CompletableFuture<ScalableTopicController> getOrCreateController(TopicName topic) {\n        String key = topic.toString();\n        CompletableFuture<ScalableTopicController> stored = controllers.computeIfAbsent(key, k -> {\n            ScalableTopicController controller = new ScalableTopicController(\n                    topic, resources, brokerService, coordinationService);\n            return controller.initialize().thenApply(__ -> controller);\n        });\n        // Evict failed futures so subsequent callers can retry. This runs *outside*\n        // computeIfAbsent, so modifying the map here is safe.\n        return stored.exceptionally(ex -> {\n            controllers.remove(key, stored);\n            throw new RuntimeException(\"Failed to initialize controller for \" + topic, ex);\n        });\n    }\n\n    /**\n     * Release the controller for a topic (e.g., on topic unload).\n     */\n    public CompletableFuture<Void> releaseController(TopicName topic) {\n        CompletableFuture<ScalableTopicController> future = controllers.remove(topic.toString());\n        if (future != null) {\n            return future.thenCompose(ScalableTopicController::close);\n        }\n        return CompletableFuture.completedFuture(null);\n    }\n\n    // --- Admin operations ---\n\n    /**\n     * Create a new scalable topic with the given number of initial segments.","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/scalable/ScalableTopicService.java#L93-L129","documentation":"ScalableTopicService.getOrCreateController asynchronously creates and initializes a per-topic controller. If controller.initialize() fails, the stored future is evicted from the cache so callers can retry, and the failure is rethrown wrapped in a RuntimeException naming the topic, preserving the original cause.","triggerScenarios":"Any of the callers (splitSegment, rebucketSegment, mergeSegments, create/deleteSubscription, seekSubscription) triggers getOrCreateController for a topic whose controller initialization throws (metadata load failure, storage error, etc.).","commonSituations":"Topic metadata corrupted or unavailable in the underlying store; broker under contention; a prior initialization left transient state that the retry now succeeds on (hence the eviction-for-retry design).","solutions":["Inspect the cause chain (getCause()) for the real initialization failure","Retry the operation — the failed future is evicted so a fresh controller is built","Check topic metadata/storage health for the named topic; unload the topic to reset state"],"exampleFix":"// handling\ntry {\n    controller = service.getOrCreateController(topic).join();\n} catch (CompletionException e) {\n    log.warn(\"controller init failed for {}\", topic, e.getCause()); // retry later\n}","handlingStrategy":"retry","validationCode":"if (!topicExists(topic)) { throw new IllegalStateException(\"Topic \" + topic + \" must exist before controller use\"); }","typeGuard":null,"tryCatchPattern":"try {\n    controller = service.getOrCreateController(topic).join();\n} catch (CompletionException e) {\n    Throwable cause = e.getCause();\n    log.warn(\"Controller init failed for {}, will retry\", topic, cause); // failure was evicted, retry is safe\n}","preventionTips":["Always inspect getCause() — the wrapper message names only the topic","Rely on the eviction design: a subsequent call rebuilds the controller","Monitor topic metadata store health; most init failures originate there"],"tags":["pulsar","scalable-topic","initialization","async"],"backgroundTag":"controller-initialization-failed","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"}