apache/pulsar · error · org.apache.pulsar.client.impl.v5.PulsarClientException
${e.getCause()}
Error message
${e.getCause()} What it means
The synchronous subscribe() joins subscribeAsync(); a CompletionException from the join is unwrapped — if the cause is a PulsarClientException it is re-thrown as-is, otherwise it is wrapped in a new PulsarClientException whose message is the cause's toString (${e.getCause()}). It indicates the subscription of the queue consumer failed for a reason outside the normal PulsarClientException set (e.g. schema/serializer failure, runtime error in builder internals).
Source
Thrown at pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/QueueConsumerBuilderV5.java:72
* one-per-segment design, which would also reject {@code topic://} scalable DLQ
* targets).
*/
private DeadLetterPolicy dlqPolicy;
QueueConsumerBuilderV5(PulsarClientV5 client, Schema<T> v5Schema) {
this.client = client;
this.v5Schema = v5Schema;
}
@Override
public QueueConsumer<T> subscribe() throws PulsarClientException {
try {
return subscribeAsync().join();
} catch (java.util.concurrent.CompletionException e) {
if (e.getCause() instanceof PulsarClientException pce) {
throw pce;
}
throw new PulsarClientException(e.getCause());
}
}
@Override
public CompletableFuture<QueueConsumer<T>> subscribeAsync() {
boolean topicSet = topicName != null && !topicName.isEmpty();
boolean namespaceSet = namespaceName != null;
if (topicSet == namespaceSet) {
return CompletableFuture.failedFuture(
new PulsarClientException.InvalidConfigurationException(
"Exactly one of .topic(name) or .namespace(...) must be set"));
}
if (conf.getSubscriptionName() == null || conf.getSubscriptionName().isEmpty()) {
return CompletableFuture.failedFuture(
new PulsarClientException.InvalidConfigurationException("Subscription name is required"));
}
if (namespaceSet) {View on GitHub (pinned to 820761864e)
Solutions
- Read the wrapped cause (printed in the message) to identify the non-standard failure
- Verify the builder state: topicName set, subscriptionName set, schema provided and matching the topic
- Fix the root cause and retry subscribe(); route broker-level failures to standard PulsarClientException handling
Example fix
// before
QueueConsumer<String> c = client.newConsumer(Schema.STRING).subscribe(); // topic never set
// after
QueueConsumer<String> c = client.newConsumer(Schema.STRING)
.topic("persistent://public/default/my-topic")
.subscriptionName("my-sub")
.subscribe(); Defensive patterns
Strategy: validation
Validate before calling
if (topicName == null || topicName.isBlank()) throw new IllegalStateException("topic must be set before subscribe");
if (subscriptionName == null || subscriptionName.isBlank()) throw new IllegalStateException("subscriptionName must be set before subscribe"); Try / catch
try {
QueueConsumer<T> c = builder.subscribe();
} catch (PulsarClientException e) {
log.error("Subscribe failed: {}", e.getMessage(), e.getCause());
} Prevention
- Set topic and subscriptionName before calling subscribe()
- Ensure the schema matches the topic's existing data
- Subscribe at startup where failures are visible, not lazily on first message
When it happens
Trigger: Calling QueueConsumerBuilderV5.subscribe() when the async subscription completes exceptionally: invalid combination of builder options (topic/subscription validation failure throwing a non-PulsarClientException like IllegalStateException), schema errors, or broker connection failures that arrive wrapped.
Common situations: Forgetting to set a topic or subscription name before subscribe(); using a schema incompatible with existing topic data; misconfigured dead-letter/retry options; broker down or authorization rejected.
Related errors
- Namespace does not exist
- Subscription has active connected consumers
- maxConsumersPerSubscription must be 0 or more
- Subscription not found
- Subscription has active connected consumers
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/b6c7636f89f0fa81.
Report an issue: GitHub.