apache/pulsar · error · IllegalArgumentException

No usable leader URL (useTls=<tls>, url=<url>, urlTls=<urlTl

Error message

No usable leader URL (useTls=<tls>, url=<url>, urlTls=<urlTls>)

What it means

WatchTcAssignmentsDiscovery.selectLeaderUri picks the leader broker URI for transaction coordinator assignments watching: the TLS variant (urlTls) when the client is configured with useTls, otherwise the plain url. If the chosen URL is null or blank, an IllegalArgumentException reports all three inputs. The broker discovery data did not provide a usable service URL for the current TLS setting.

Source

Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/transaction/WatchTcAssignmentsDiscovery.java:235

    private void scheduleReconnect() {
        if (closed) {
            return;
        }
        long delayMs = reconnectBackoff.next().toMillis();
        pulsarClient.timer().newTimeout(timeout -> openWatch(), delayMs, TimeUnit.MILLISECONDS);
    }

    /**
     * Pick the leader URL matching the client's TLS setting and parse it. Throws if no usable URL is
     * present (e.g. a non-TLS client and a TLS-only leader) — the caller skips that partition rather
     * than tearing down the watch.
     */
    private URI selectLeaderUri(String url, String urlTls) {
        boolean tls = pulsarClient.getConfiguration().isUseTls();
        String chosen = tls && urlTls != null && !urlTls.isBlank() ? urlTls : url;
        if (chosen == null || chosen.isBlank()) {
            throw new IllegalArgumentException("No usable leader URL (useTls=" + tls
                    + ", url=" + url + ", urlTls=" + urlTls + ")");
        }
        return URI.create(chosen);
    }

    @Override
    public TransactionMetaStoreHandler handlerForCoordinator(long tcId) {
        return handlers.get(tcId);
    }

    @Override
    public TransactionMetaStoreHandler nextHandler() {
        int n = parallelism;
        if (n <= 0) {
            return null;
        }
        // Round-robin over coordinator ids 0..parallelism-1, skipping any mid-election gap.
        for (int attempt = 0; attempt < n; attempt++) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Configure the broker's TLS web service URL (webServiceUrlTls=https://...) so urlTls is populated when useTls=true.
  2. Set the client's serviceUrl to match the advertised scheme (https://... when useTls) or disable useTls.
  3. Verify the discovery response actually contains a non-empty serviceUrl; check broker registration config.
  4. If you control the lookup, ensure advertisedListeners/serviceUrl fields are correctly set on the broker.

Example fix

// before (broker.conf)
webServiceUrl=http://host:8080
// after (when clients use TLS)
webServiceUrlTls=https://host:8443
Defensive patterns

Strategy: validation

Validate before calling

boolean usable(String u) { return u != null && !u.isBlank(); }
String url = discovery.getUrl(), urlTls = discovery.getUrlTls();
boolean ok = clientConf.isUseTls() ? usable(urlTls) || usable(url) : usable(url);
if (!ok) throw new IllegalStateException("Discovery gave no usable service URL");

Try / catch

try {
    watchTcAssignments();
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("No usable leader URL")) {
        log.error("Broker missing serviceUrl/webServiceUrlTls for useTls=" + useTls, e);
    }
}

Prevention

When it happens

Trigger: Receiving a discovery event where url (and urlTls, when useTls=true) is null/empty, then attempting to derive the leader URI for the watch.

Common situations: Broker advertising only a plain HTTP service URL while the client requires TLS (useTls=true, no tls service URL configured); broker misconfiguration missing webServiceUrl/webServiceUrlTls; discovery data truncated or from an older broker version.

Understand the failure class

Related errors


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