{"record":{"id":"887c9eb497f1e314","repo":"apache/pulsar","slug":"no-usable-leader-url-usetls-tls-url-url-url","errorCode":null,"errorMessage":"No usable leader URL (useTls=<tls>, url=<url>, urlTls=<urlTls>)","messagePattern":"No usable leader URL \\(useTls=<tls>, url=<url>, urlTls=<urlTls>\\)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-client/src/main/java/org/apache/pulsar/client/impl/transaction/WatchTcAssignmentsDiscovery.java","lineNumber":235,"sourceCode":"\n    private void scheduleReconnect() {\n        if (closed) {\n            return;\n        }\n        long delayMs = reconnectBackoff.next().toMillis();\n        pulsarClient.timer().newTimeout(timeout -> openWatch(), delayMs, TimeUnit.MILLISECONDS);\n    }\n\n    /**\n     * Pick the leader URL matching the client's TLS setting and parse it. Throws if no usable URL is\n     * present (e.g. a non-TLS client and a TLS-only leader) — the caller skips that partition rather\n     * than tearing down the watch.\n     */\n    private URI selectLeaderUri(String url, String urlTls) {\n        boolean tls = pulsarClient.getConfiguration().isUseTls();\n        String chosen = tls && urlTls != null && !urlTls.isBlank() ? urlTls : url;\n        if (chosen == null || chosen.isBlank()) {\n            throw new IllegalArgumentException(\"No usable leader URL (useTls=\" + tls\n                    + \", url=\" + url + \", urlTls=\" + urlTls + \")\");\n        }\n        return URI.create(chosen);\n    }\n\n    @Override\n    public TransactionMetaStoreHandler handlerForCoordinator(long tcId) {\n        return handlers.get(tcId);\n    }\n\n    @Override\n    public TransactionMetaStoreHandler nextHandler() {\n        int n = parallelism;\n        if (n <= 0) {\n            return null;\n        }\n        // Round-robin over coordinator ids 0..parallelism-1, skipping any mid-election gap.\n        for (int attempt = 0; attempt < n; attempt++) {","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client/src/main/java/org/apache/pulsar/client/impl/transaction/WatchTcAssignmentsDiscovery.java#L217-L253","documentation":"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.","triggerScenarios":"Receiving a discovery event where url (and urlTls, when useTls=true) is null/empty, then attempting to derive the leader URI for the watch.","commonSituations":"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.","solutions":["Configure the broker's TLS web service URL (webServiceUrlTls=https://...) so urlTls is populated when useTls=true.","Set the client's serviceUrl to match the advertised scheme (https://... when useTls) or disable useTls.","Verify the discovery response actually contains a non-empty serviceUrl; check broker registration config.","If you control the lookup, ensure advertisedListeners/serviceUrl fields are correctly set on the broker."],"exampleFix":"// before (broker.conf)\nwebServiceUrl=http://host:8080\n// after (when clients use TLS)\nwebServiceUrlTls=https://host:8443","handlingStrategy":"validation","validationCode":"boolean usable(String u) { return u != null && !u.isBlank(); }\nString url = discovery.getUrl(), urlTls = discovery.getUrlTls();\nboolean ok = clientConf.isUseTls() ? usable(urlTls) || usable(url) : usable(url);\nif (!ok) throw new IllegalStateException(\"Discovery gave no usable service URL\");","typeGuard":null,"tryCatchPattern":"try {\n    watchTcAssignments();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"No usable leader URL\")) {\n        log.error(\"Broker missing serviceUrl/webServiceUrlTls for useTls=\" + useTls, e);\n    }\n}","preventionTips":["Configure webServiceUrlTls on brokers when clients use TLS","Keep client serviceUrl scheme consistent with useTls","Inspect discovery payloads in tests for null/blank URLs","Pin broker/client versions when listener advertisement schemas change"],"tags":["tls","url","discovery","transaction"],"backgroundTag":"missing-service-url","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}