apache/pulsar · error · RestException
Failed to find ownership for topic:%s
Error message
Failed to find ownership for topic:%s
What it means
validateTopicOwnershipAsync performs a topic lookup; if the lookup returns no result (no broker owns or could acquire the topic), it throws 412 PRECONDITION_FAILED 'Failed to find ownership for topic:...'. With readOnly=false the broker normally tries to acquire ownership, so an empty lookup signals lookup/registration failure rather than a benign 'not owned yet'.
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/web/PulsarWebResource.java:736
*/
protected void validateTopicOwnership(TopicName topicName, boolean authoritative) {
sync(()-> validateTopicOwnershipAsync(topicName, authoritative));
}
protected CompletableFuture<Void> validateTopicOwnershipAsync(TopicName topicName, boolean authoritative) {
NamespaceService nsService = pulsar().getNamespaceService();
LookupOptions options = LookupOptions.builder()
.authoritative(authoritative)
.webServiceAdvertisedListenerName(getWebServiceListenerName())
.readOnly(false)
.build();
return nsService.getLookupResultForWebRequestAsync(topicName, options)
.thenApply(optLookupResult ->
optLookupResult.orElseThrow(() -> {
log.info("Unable to get web service url");
throw new RestException(Status.PRECONDITION_FAILED,
"Failed to find ownership for topic:" + topicName);
})
).thenCompose(lookupResult -> nsService.isServiceUnitOwnedAsync(topicName)
.thenApply(isTopicOwned -> Pair.of(lookupResult, isTopicOwned))
).thenAccept(pair -> {
LookupResult lookupResult = pair.getLeft();
boolean isTopicOwned = pair.getRight();
if (!isTopicOwned) {
boolean newAuthoritative = isLeaderBroker(pulsar());
URI redirect = lookupResult.toRedirectUri(uri.getRequestUri(), newAuthoritative);
// 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
- Retry after a short delay so a broker can acquire the topic's bundle
- Confirm brokers are alive and registered (pulsar-admin brokers list)
- Check advertisedAddress/webservicePort/listener config if logs show 'Unable to get web service url'
- Let the broker redirect: follow the 307 Temporary Redirect responses rather than forcing requests to a fixed broker
Defensive patterns
Strategy: retry
Validate before calling
// Verify brokers are registered and the topic exists before ownership-sensitive admin calls
if (admin.brokers().getActiveBrokers().length == 0) throw new IllegalStateException("no brokers");
admin.namespaces().getTopics(ns); // confirms namespace served; topic existence check for non-partitioned Try / catch
try {
admin.topics().getStats(topic);
} catch (PulsarAdminException.PreconditionFailedException e) {
if (e.getMessage().startsWith("Failed to find ownership for topic")) {
retryWithBackoff(() -> admin.topics().getStats(topic), 3);
} else throw e;
} Prevention
- Follow HTTP 307 redirects from the admin API instead of pinning a broker
- Retry with backoff after broker restarts/failovers
- Ensure advertisedAddress and listener web service URLs are correct cluster-wide
When it happens
Trigger: Admin REST calls on a topic (stats, terminate, delete, permissions) when getLookupResultForWebRequestAsync yields empty Optional — topic's namespace bundle has no owning broker, broker registration missing, or the advertised web service URL can't be produced.
Common situations: Right after broker restart or namespace unload when ownership isn't established; cluster with no live brokers; advertised listeners/service URL misconfiguration; partitions whose parent topic's bundle is being migrated; client hitting a broker that isn't in the same cluster as the topic's owner.
Related errors
- Can't find owner for topic %s
- Failed to find ownership for ServiceUnit:%s
- Topic name is not valid
- Partitioned Topic Name should not contain '-partition-'
- Cluster ${cluster} does not exist.
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/81ac3bfea46aff62.
Report an issue: GitHub.