apache/pulsar · error · RestException

Failed to find ownership for ServiceUnit:%s

Error message

Failed to find ownership for ServiceUnit:%s

What it means

validateBundleOwnershipAsync asks the load manager for a lookup result for the namespace bundle; if no broker currently owns (or is acquiring) that bundle, the Optional is empty and the resource throws 412 PRECONDITION_FAILED 'Failed to find ownership for ServiceUnit:...'. Normally an unowned bundle would be acquired, so this usually indicates the lookup machinery could not determine an owner.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/web/PulsarWebResource.java:688

            boolean authoritative, boolean readOnly) {
        return validateNamespaceBundleRangeAsync(fqnn, bundleRange)
                .thenCompose(nsBundle -> validateBundleOwnershipAsync(nsBundle, authoritative, readOnly)
                        .thenApply(__ -> nsBundle));
    }

    public CompletableFuture<Void> validateBundleOwnershipAsync(NamespaceBundle bundle, boolean authoritative,
                                                                boolean readOnly) {
        NamespaceService nsService = pulsar().getNamespaceService();
        LookupOptions options = LookupOptions.builder()
                .authoritative(authoritative)
                .webServiceAdvertisedListenerName(getWebServiceListenerName())
                .readOnly(readOnly)
                .build();
        return nsService.getLookupResultForWebRequestAsync(bundle, options)
                .thenCompose(optLookupResult -> {
                    if (optLookupResult.isEmpty()) {
                        log.warn("Unable to get web service url");
                        throw new RestException(Status.PRECONDITION_FAILED,
                                "Failed to find ownership for ServiceUnit:" + bundle.toString());
                    }
                    LookupResult lookupResult = optLookupResult.get();
                    return nsService.isServiceUnitOwnedAsync(bundle)
                            .thenAccept(owned -> {
                                if (!owned) {
                                    boolean newAuthoritative = this.isLeaderBroker();
                                    UriBuilder uriBuilder = UriBuilder.fromUri(
                                            lookupResult.toRedirectUri(uri.getRequestUri(), newAuthoritative));
                                    if (!ExtensibleLoadManagerImpl.isLoadManagerExtensionEnabled(pulsar)) {
                                        uriBuilder.replaceQueryParam("destinationBroker");
                                    }
                                    URI redirect = uriBuilder.build();
                                    log.debug().attr("bundle", bundle).log("is not a service unit owned");
                                    // Redirect
                                    log.debug().attr("redirect", redirect).log("Redirecting the rest call");
                                    throw new WebApplicationException(Response.temporaryRedirect(redirect).build());
                                }

View on GitHub (pinned to 820761864e)

Solutions

  1. Retry the request shortly after — ownership may settle once a broker acquires the bundle
  2. Check broker availability and namespace status (pulsar-admin namespaces topics / broker stats)
  3. Verify advertisedAddress/listeners and webServiceUrl config so lookups can resolve ('Unable to get web service url' preceding this error)
  4. If a bundle is stuck, unload it: pulsar-admin namespaces unload <ns> --bundle <range>

Example fix

// before (immediately after unload, request fails 412)
// after: wait and retry with backoff
sleep 5s; pulsar-admin namespaces split-bundle my-tenant/ns/0x00000000_0xffffffff --unload
Defensive patterns

Strategy: retry

Validate before calling

// Check the namespace has an owner before bundle operations
List<String> bundles = admin.namespaces().getBundles(ns); // throws if namespace unassigned
// also confirm brokers are registered
if (admin.brokers().getActiveBrokers().length == 0) throw new IllegalStateException("no brokers available");

Try / catch

CompletableFuture
    .supplyAsync(() -> doBundleOperation(bundle))
    .exceptionallyCompose(ex -> {
        if (isPreconditionFailed(ex) && ex.getMessage().contains("Failed to find ownership for ServiceUnit")) {
            return CompletableFuture.delayedExecutor(5, SECONDS)
                .thenCompose(v -> doBundleOperation(bundle)); // bounded retries
        }
        return CompletableFuture.failedFuture(ex);
    });

Prevention

When it happens

Trigger: Admin operations on a namespace bundle (split/unload/clear-backlog under a bundle range) when getLookupResultForWebRequestAsync returns empty — e.g. namespace unloaded concurrently, no broker available to own the bundle, or lookup failing due to load-manager/service-url issues.

Common situations: Race with bundle unload/delete operations; namespace bundle data stale after broker restart; all brokers of the cluster down or registering slowly after failover; misconfigured advertised listeners so the lookup cannot produce a web service URL ('Unable to get web service url' in logs).

Related errors


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