openzipkin/zipkin · critical · RuntimeException
Pulsar client creation failed. {}
Error message
Pulsar client creation failed. {} What it means
LazyPulsarInit.subscribe() wraps any exception thrown while building the PulsarClient in a RuntimeException ('Pulsar client creation failed. ...'). PulsarClient.builder().loadConf(clientProps).build() fails on an invalid/unreachable serviceUrl, missing required config, bad auth settings, or incompatible client/broker versions. The CheckResult is also recorded as failed so the collector's check() reports unhealthy.
Source
Thrown at zipkin-collector/pulsar/src/main/java/zipkin2/collector/pulsar/LazyPulsarInit.java:53
void init() {
if (result == null) {
synchronized (this) {
if (result == null) {
result = subscribe();
}
}
}
}
private PulsarClient subscribe() {
PulsarClient client;
try {
client = PulsarClient.builder()
.loadConf(clientProps)
.build();
} catch (Exception e) {
failure.set(CheckResult.failed(e));
throw new RuntimeException("Pulsar client creation failed. " + e.getMessage(), e);
}
try {
for (int i = 0; i < concurrency; i++) {
PulsarSpanConsumer consumer = new PulsarSpanConsumer(topic, consumerProps, client, collector, metrics);
consumer.startConsumer();
}
return client;
} catch (Exception e) {
try {
client.close();
} catch (PulsarClientException ex) {
// Nobody cares me.
}
failure.set(CheckResult.failed(e));
throw new RuntimeException("Pulsar Client is unable to subscribe to the topic(" + topic + "), please check the service.", e);
}
}View on GitHub (pinned to 878ce2a1fa)
Solutions
- Verify the serviceUrl format, e.g. pulsar://my-broker:6650, and that the broker host:port is reachable (telnet/grpcurl)
- Check the wrapped cause (e) in the stack trace — it names the real PulsarClientException reason
- Validate TLS/authentication settings in clientProps against the broker configuration
- Check client/broker version compatibility if the cause indicates an unsupported protocol
Example fix
// before
PulsarCollector.newBuilder(ctx)
.serviceUrl("my-broker:6650") // missing scheme
...
// after
PulsarCollector.newBuilder(ctx)
.serviceUrl("pulsar://my-broker:6650")
... Defensive patterns
Strategy: try-catch
Validate before calling
// Validate the URL shape before building the collector
URI uri = URI.create(serviceUrl);
if (!("pulsar".equals(uri.getScheme()) || "http".equals(uri.getScheme()) || "https".equals(uri.getScheme()))) {
throw new IllegalArgumentException("serviceUrl must start with pulsar:// or http(s)://");
} Try / catch
try {
collector.check(); // triggers lazy init
} catch (RuntimeException e) {
Throwable cause = e.getCause();
log.error("Pulsar client init failed: {}", cause.getMessage(), e);
// surface as unhealthy and let orchestration restart/backoff
} Prevention
- Pre-flight the serviceUrl scheme and network reachability before wiring the collector
- Log and inspect the wrapped cause — the real PulsarClientException explains the failure
- Run the collector behind a health check so a failed lazy init shows up as unhealthy rather than silent
When it happens
Trigger: PulsarCollector built with a malformed serviceUrl (not pulsar://host:port or http://...), a broker that is unreachable at connect time, invalid TLS/auth configuration in clientProps, or a Pulsar client version mismatch. The error surfaces lazily on first use (check()/accept of the first span), not at build().
Common situations: Service URL typo (e.g. missing pulsar:// scheme), broker DNS not resolvable in Kubernetes, TLS enabled broker with plaintext client config, or auth plugin not on the classpath.
Related errors
- serviceUrl is null or empty
- clientProps is empty
- consumerProps is empty
- metrics == null
- connectionFactory == null
AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14).
Data as JSON: /api/errors/eac39947261ec723.
Report an issue: GitHub.