apache/pulsar · error · PulsarClientException.InvalidConfigurationException

Can't use batch receive, if the queue size is 0

Error message

Can't use batch receive, if the queue size is 0

What it means

batchReceive() requires a non-zero receiver queue size because the batch receive fills a collection from the consumer's internal queue; with receiverQueueSize=0 there is nowhere to buffer messages, so the client rejects the call up front with InvalidConfigurationException.

Source

Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java:1048

            case Closed:
                throw  new PulsarClientException.AlreadyClosedException("Consumer already closed");
            case Terminated:
                throw new PulsarClientException.AlreadyClosedException("Topic was terminated");
            case Failed:
            case Uninitialized:
                throw new PulsarClientException.NotConnectedException();
            default:
                break;
        }
    }

    private void verifyBatchReceive() throws PulsarClientException {
        if (listener != null) {
            throw new PulsarClientException.InvalidConfigurationException(
                "Cannot use receive() when a listener has been set");
        }
        if (getCurrentReceiverQueueSize() == 0) {
            throw new PulsarClientException.InvalidConfigurationException(
                "Can't use batch receive, if the queue size is 0");
        }
    }

    protected static final class OpBatchReceive<T> {

        final CompletableFuture<Messages<T>> future;
        final long createdAt;

        private OpBatchReceive(CompletableFuture<Messages<T>> future) {
            this.future = future;
            this.createdAt = System.nanoTime();
        }

        static <T> OpBatchReceive<T> of(CompletableFuture<Messages<T>> future) {
            return new OpBatchReceive<>(future);
        }
    }

View on GitHub (pinned to 820761864e)

Solutions

  1. Set receiverQueueSize to a positive value (default 1000) in the ConsumerBuilder.
  2. Use plain receive()/receiveAsync() instead of batchReceive() when the queue size must remain 0.

Example fix

// before
Consumer<byte[]> c = client.newConsumer().receiverQueueSize(0).subscribe();
Messages<byte[]> msgs = c.batchReceive();
// after
Consumer<byte[]> c = client.newConsumer().receiverQueueSize(100).subscribe();
Messages<byte[]> msgs = c.batchReceive();
Defensive patterns

Strategy: validation

Validate before calling

if (consumer.getQueueSize() == 0) { /* use receive() instead of batchReceive() */ }

Try / catch

try {
  Messages<byte[]> msgs = consumer.batchReceive();
} catch (PulsarClientException.InvalidConfigurationException e) {
  // receiverQueueSize is 0: switch to receiveAsync()
}

Prevention

When it happens

Trigger: Calling batchReceive() or batchReceiveAsync() on a consumer whose getCurrentReceiverQueueSize() is 0 — typically after ConsumerBuilder.receiverQueueSize(0) (often combined with a Key_Shared/exclusive pattern or memory-constrained setups).

Common situations: Setting receiverQueueSize(0) to get strict per-message ordering or low-latency behavior, then later adding batchReceive for throughput; copying configs between consumers.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/47eb23adc129d8ea. Report an issue: GitHub.