{"record":{"id":"b380d0a76ad7d359","repo":"apache/pulsar","slug":"fieldname-must-use-the-broker-binary-protocol","errorCode":null,"errorMessage":"${fieldName} must use the broker binary protocol (pulsar:// or pulsar+ssl://); got '${url}'. This looks like the admin/web service URL — pass the broker service URL instead (typically port 6650, or 6651 for TLS).","messagePattern":"(.+?) must use the broker binary protocol \\(pulsar:// or pulsar\\+ssl://\\); got '(.+?)'\\. This looks like the admin/web service URL — pass the broker service URL instead \\(typically port 6650, or 6651 for TLS\\)\\.","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/PulsarClientBuilderV5.java","lineNumber":591,"sourceCode":"        return conf;\n    }\n\n    /**\n     * Reject anything that isn't the broker binary protocol. The most common\n     * mistake is passing the admin/web service URL ({@code http://...}) where a\n     * broker URL is expected — call that out specifically. The v4 client used to\n     * silently fail far downstream with cryptic connection errors; here we fail\n     * fast at configure time with a message the user can act on.\n     */\n    private static void validatePulsarServiceUrl(String url, String fieldName) {\n        if (url == null || url.isBlank()) {\n            throw new IllegalArgumentException(fieldName + \" must not be null or blank\");\n        }\n        if (url.startsWith(\"pulsar://\") || url.startsWith(\"pulsar+ssl://\")) {\n            return;\n        }\n        if (url.startsWith(\"http://\") || url.startsWith(\"https://\")) {\n            throw new IllegalArgumentException(fieldName + \" must use the broker binary protocol \"\n                    + \"(pulsar:// or pulsar+ssl://); got '\" + url + \"'. This looks like the admin/web \"\n                    + \"service URL — pass the broker service URL instead (typically port 6650, or \"\n                    + \"6651 for TLS).\");\n        }\n        throw new IllegalArgumentException(fieldName + \" must use the broker binary protocol \"\n                + \"(pulsar:// or pulsar+ssl://); got '\" + url + \"'.\");\n    }\n}\n","sourceCodeStart":573,"sourceCodeEnd":600,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/PulsarClientBuilderV5.java#L573-L600","documentation":"The v5 builder validates that the service URL uses the broker binary protocol (pulsar:// or pulsar+ssl://). An http:// or https:// URL is almost always the admin/web service URL (port 8080/6651-style web endpoint), which would otherwise cause confusing downstream connection failures; the builder rejects it at configure time and tells you to use the broker URL (typically port 6650, or 6651 for TLS). Any other scheme gets the same message without the 'admin/web' hint.","triggerScenarios":"Calling builder.serviceUrl(\"http://broker:8080\") or serviceUrl(\"https://...\") — or connectionPolicy with a proxyServiceUrl of that shape — then build()/further configuration triggers the validation immediately.","commonSituations":"Copy-pasting the admin URL from broker.conf (webServiceUrl) or from a Pulsar Admin client example; using the standalone-service URL from docker-compose; confusing the REST proxy endpoint with the binary endpoint; defaulting to port 8080 from other middleware.","solutions":["Replace the URL with the broker binary URL: pulsar://host:6650 (or pulsar+ssl://host:6651 for TLS).","Keep the http(s) URL only for the PulsarAdmin client, not the messaging client.","Check broker.conf: webServiceUrl (http) is for admin, brokerServiceUrl (pulsar://) is what the client needs.","If you need to connect through a proxy, set proxyServiceUrl within ConnectionPolicy with a pulsar:// URL and the matching proxyProtocol, not an http URL."],"exampleFix":"// before\nPulsarClient c = PulsarClient.builder()\n        .serviceUrl(\"http://localhost:8080\") // admin URL -> IllegalArgumentException\n        .build();\n// after\nPulsarClient c = PulsarClient.builder()\n        .serviceUrl(\"pulsar://localhost:6650\")\n        .build();","handlingStrategy":"validation","validationCode":"String url = envOrConfig(\"serviceUrl\");\nif (url != null && (url.startsWith(\"http://\") || url.startsWith(\"https://\"))) {\n    throw new IllegalStateException(\"serviceUrl must be pulsar://... — \" + url + \" looks like the admin URL\");\n}","typeGuard":"static boolean isBrokerUrl(String u) {\n    return u != null && (u.startsWith(\"pulsar://\") || u.startsWith(\"pulsar+ssl://\"));\n}","tryCatchPattern":"try {\n    builder.serviceUrl(url);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"broker binary protocol\")) {\n        throw new IllegalStateException(\"Point the messaging client at pulsar://host:6650, not the admin URL\", e);\n    }\n    throw e;\n}","preventionTips":["Keep admin URL and broker URL as separate named config keys (adminUrl vs serviceUrl).","Broker port is typically 6650 (6651 for TLS); admin/web is 8080 — check broker.conf's brokerServiceUrl.","Add a scheme check helper in shared client-factory code.","For proxies, use ConnectionPolicy.proxyServiceUrl with a pulsar:// URL plus proxyProtocol, not an http URL."],"tags":["pulsar","configuration","service-url","protocol","validation"],"backgroundTag":"wrong-service-url-protocol","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"}