apache/pulsar · error · org.apache.pulsar.client.impl.v5.PulsarClientException
${cause}
Error message
${cause} What it means
ProducerBuilderV5.create() blocks on createAsync() and unwraps the CompletionException. Any failure from the async producer-creation pipeline (DAG watch session start, topic layout fetch, segment attach) that is not already a v5 PulsarClientException is rethrown as a plain v5 PulsarClientException wrapping the original cause. It is the library's way of keeping the checked-exception surface uniform across the sync create() path.
Source
Thrown at pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/ProducerBuilderV5.java:65
ProducerBuilderV5(PulsarClientV5 client, Schema<T> v5Schema) {
this.client = client;
this.v5Schema = v5Schema;
}
@Override
public Producer<T> create() throws PulsarClientException {
try {
return createAsync().join();
} catch (java.util.concurrent.CompletionException e) {
Throwable cause = e.getCause();
if (cause instanceof PulsarClientException pce) {
throw pce;
}
if (cause instanceof org.apache.pulsar.client.api.PulsarClientException.NotFoundException) {
throw new PulsarClientException.NotFoundException(cause.getMessage());
}
throw new PulsarClientException(cause);
}
}
@Override
public CompletableFuture<Producer<T>> createAsync() {
String topicStr = conf.getTopicName();
if (topicStr == null || topicStr.isEmpty()) {
return CompletableFuture.failedFuture(
new PulsarClientException.InvalidConfigurationException("Topic name is required"));
}
TopicName topicName = V5Utils.parseScalableTopicInput(topicStr);
// Create DAG watch client and start the session
DagWatchClient dagWatch = new DagWatchClient(client.v4Client(), topicName);
return dagWatch.start()
.thenCompose(initialLayout -> {View on GitHub (pinned to 820761864e)
Solutions
- Read the wrapped cause via e.getCause() (or print the full stack trace) to see the real failure; fix that root problem.
- If the cause is 'topic not found', create the topic or enable auto-creation on the broker.
- Verify broker connectivity (serviceUrl, TLS config) before create(); the v5 client connects lazily during producer creation.
- For transient network errors, retry create() with backoff; for configuration errors, fix the builder settings instead.
Example fix
// before
Producer<T> p = client.newProducer(schema).topic(topic).create(); // opaque PulsarClientException
// after
try {
Producer<T> p = client.newProducer(schema).topic(topic).create();
} catch (PulsarClientException e) {
LOG.error("producer create failed", e.getCause() != null ? e.getCause() : e);
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
if (topic == null || topic.isEmpty()) throw new IllegalArgumentException("topic required before create()"); Try / catch
try {
Producer<T> p = builder.create();
} catch (PulsarClientException e) {
Throwable root = e.getCause() != null ? e.getCause() : e;
if (root instanceof java.util.concurrent.CompletionException ce) root = ce.getCause();
LOG.error("producer creation failed: {}", root.toString(), root);
throw e;
} Prevention
- Always set topic() before create(); the async path rejects it earlier with InvalidConfigurationException.
- Log the full cause chain — create() wraps non-PulsarClientException causes.
- Verify broker connectivity with a small health check before creating producers at startup.
- Distinguish retryable (network) from permanent (config) causes before retrying.
When it happens
Trigger: Calling producerBuilder.create() when the async pipeline fails with a non-PulsarClientException: e.g. the broker rejects the topic (v4 NotFoundException is mapped specially), a connection drops mid-attach, a timeout in DagWatchClient.start(), or any RuntimeException bubbling out of eagerAttachInitialAsync().
Common situations: Topic does not exist and auto-creation is disabled; broker unreachable or TLS handshake failure during segment attach; schema/serialization setup errors; a v4 client that was closed while a producer was being created.
Related errors
- Failed to initialize controller for ${topic}
- When 'messageRoutingMode' is CustomPartition, 'messageRouter
- When 'messageRouter' is set, 'messageRoutingMode' should be
- ${cause.getMessage()}
- ${e.getMessage()}
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/0fa08506aa6c6ac8.
Report an issue: GitHub.