apache/pulsar · error · IllegalStateException

No available broker found.

Error message

No available broker found.

What it means

During load-manager migration, RedirectManagerForLoadManagerMigration.redirectIfLoadBalancerOnBrokerIsNotExpected fetches the available-broker lookup data; if the map is empty there is no broker to redirect to or to evaluate, so the returned future fails with IllegalStateException 'No available broker found.'

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/loadbalance/extensions/manager/RedirectManagerForLoadManagerMigration.java:104

     * Redirect the request to another broker if the load balancer on the current broker is using the load manager
     * of the latest service lookup data available in the metadata store.
     *
     * @param options lookup options
     * @return lookup result
     */
    public CompletableFuture<Optional<LookupResult>> redirectIfLoadBalancerOnBrokerIsNotExpected(
            LookupOptions options) {
        if (!pulsar.getConfiguration().isLoadManagerMigrationEnabled()) {
            // no-op when load manager migration is disabled.
            return CompletableFuture.completedFuture(Optional.empty());
        }
        String currentLMClassName = pulsar.getConfiguration().getLoadManagerClassName();
        boolean debug = ExtensibleLoadManagerImpl.debug(pulsar.getConfiguration(), log);
        return getAvailableBrokerLookupDataAsync().thenApply(lookupDataMap -> {
            if (lookupDataMap.isEmpty()) {
                String errorMsg = "No available broker found.";
                log.warn(errorMsg);
                throw new IllegalStateException(errorMsg);
            }
            AtomicReference<BrokerLookupData> latestServiceLookupData = new AtomicReference<>();
            AtomicLong lastStartTimestamp = new AtomicLong(0L);
            lookupDataMap.forEach((key, value) -> {
                if (lastStartTimestamp.get() <= value.getStartTimestamp()) {
                    lastStartTimestamp.set(value.getStartTimestamp());
                    latestServiceLookupData.set(value);
                }
            });
            if (latestServiceLookupData.get() == null) {
                String errorMsg = "No latest service lookup data found.";
                log.warn(errorMsg);
                throw new IllegalStateException(errorMsg);
            }

            if (Objects.equals(latestServiceLookupData.get().getLoadManagerClassName(), currentLMClassName)) {
                if (debug) {
                    log.info().attr("name", currentLMClassName)

View on GitHub (pinned to 820761864e)

Solutions

  1. Wait for brokers to start and publish load data, then retry the lookup.
  2. Check broker logs and the metadata store (e.g. /loadbalance/brokers in ZooKeeper et al.) for registered brokers; fix connectivity if empty.
  3. Ensure at least one broker is running and registered with the ExtensibleLoadManager before sending lookups.
  4. Catch the IllegalStateException in the lookup path and return a 503 'Service unavailable' style response to clients.

Example fix

// before
return redirectIfLoadBalancerOnBrokerIsNotExpected(...);
// after
return redirectIfLoadBalancerOnBrokerIsNotExpected(...)
    .exceptionally(ex -> {
        if (ex.getCause() instanceof IllegalStateException) {
            throw new RestException(Response.Status.SERVICE_UNAVAILABLE, "No available brokers");
        }
        throw FutureUtil.wrapToCompletionException(ex);
    });
Defensive patterns

Strategy: try-catch

Validate before calling

boolean hasBrokers = brokerRegistry.snapshot().values().stream()
    .anyMatch(d -> !d.isBrokerShuttingDown());
if (!hasBrokers) { /* defer/redirect with 503 */ }

Try / catch

redirectIfLoadBalancerOnBrokerIsNotExpected(...)
  .exceptionally(ex -> {
      Throwable c = FutureUtil.unwrapCompletionException(ex);
      if (c instanceof IllegalStateException && c.getMessage().contains("No available broker")) {
          throw new RestException(Response.Status.SERVICE_UNAVAILABLE, c.getMessage());
      }
      throw FutureUtil.wrapToCompletionException(c);
  });

Prevention

When it happens

Trigger: A lookup reaches redirectIfLoadBalancerOnBrokerIsNotExpected while getAvailableBrokerLookupDataAsync returns an empty map (no brokers registered in the extensible load manager's broker registry).

Common situations: Cluster just started and no broker has published load data yet, metadata store connectivity issues wiped/emptied the registry, or all brokers were excluded/deregistered (shutdown, crash).

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/4e7a8c80db4c002b. Report an issue: GitHub.