apache/pulsar · error · RuntimeException
Failed to initialize controller for ${topic}
Error message
Failed to initialize controller for ${topic} What it means
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.
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/service/scalable/ScalableTopicService.java:111
// --- Controller management ---
/**
* Get or create a controller for a scalable topic. The controller will attempt
* leader election; only the leader actively coordinates consumers.
*/
public CompletableFuture<ScalableTopicController> getOrCreateController(TopicName topic) {
String key = topic.toString();
CompletableFuture<ScalableTopicController> stored = controllers.computeIfAbsent(key, k -> {
ScalableTopicController controller = new ScalableTopicController(
topic, resources, brokerService, coordinationService);
return controller.initialize().thenApply(__ -> controller);
});
// Evict failed futures so subsequent callers can retry. This runs *outside*
// computeIfAbsent, so modifying the map here is safe.
return stored.exceptionally(ex -> {
controllers.remove(key, stored);
throw new RuntimeException("Failed to initialize controller for " + topic, ex);
});
}
/**
* Release the controller for a topic (e.g., on topic unload).
*/
public CompletableFuture<Void> releaseController(TopicName topic) {
CompletableFuture<ScalableTopicController> future = controllers.remove(topic.toString());
if (future != null) {
return future.thenCompose(ScalableTopicController::close);
}
return CompletableFuture.completedFuture(null);
}
// --- Admin operations ---
/**
* Create a new scalable topic with the given number of initial segments.View on GitHub (pinned to 820761864e)
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
Example fix
// handling
try {
controller = service.getOrCreateController(topic).join();
} catch (CompletionException e) {
log.warn("controller init failed for {}", topic, e.getCause()); // retry later
} Defensive patterns
Strategy: retry
Validate before calling
if (!topicExists(topic)) { throw new IllegalStateException("Topic " + topic + " must exist before controller use"); } Try / catch
try {
controller = service.getOrCreateController(topic).join();
} catch (CompletionException e) {
Throwable cause = e.getCause();
log.warn("Controller init failed for {}, will retry", topic, cause); // failure was evicted, retry is safe
} Prevention
- 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
When it happens
Trigger: 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.).
Common situations: 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).
Related errors
- Must have at least 1 segment
- Segment not found: ${segmentId}
- Cannot split non-active segment: ${segmentId}
- Could not instantiate ${cls.getName()} either with or withou
- ${cause}
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/7bb537cae997f557.
Report an issue: GitHub.