apache/pulsar · warning · PulsarClientException

Receive interrupted

Error message

Receive interrupted

What it means

V5ReceiveQueue.take() blocks on receiveAsync().get(). If the waiting thread is interrupted while blocked, the interrupt status is restored and a PulsarClientException with the fixed message "Receive interrupted" is thrown. ExecutionException causes are unwrapped and rethrown via unwrap(e) instead.

Solutions

  1. Handle PulsarClientException in the receive loop and check Thread.currentThread().isInterrupted() to exit cleanly.
  2. Use poll(Duration) with a timeout instead of indefinite take() so shutdown can be detected without interrupts.
  3. Ensure a producer is actually publishing to the topic; idle topics make take() wait indefinitely until interrupted.
  4. Prefer receiveMulti(maxMessages, timeout) for batch consumption with bounded waiting.

Example fix

// before
while (running) {
    Message<String> msg = queue.take(); // throws on interrupt
    handle(msg);
}
// after
while (running) {
    Message<String> msg = queue.poll(Duration.ofSeconds(1));
    if (msg == null) continue;
    handle(msg);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (Thread.currentThread().isInterrupted()) {
    // don't enter a blocking take with a pending interrupt
    throw new PulsarClientException("interrupted before take");
}

Try / catch

try {
    Message<T> msg = queue.take();
} catch (PulsarClientException e) {
    if (Thread.currentThread().isInterrupted()) return; // shutdown path
    throw e;
}

Prevention

When it happens

Trigger: Calling take() and having the thread interrupted while waiting for the next message — consumer closed, executor shutdown, or another thread calling interrupt().

Common situations: Consumer loop threads interrupted during application shutdown; watchdogs interrupting threads that appear stuck waiting for messages that never arrive (no producers publishing); test timeouts cancelling receive loops.

Related errors


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

Appendix: source

Thrown at pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/V5ReceiveQueue.java:272

            Message<T> m;
            while (batch.size() < max && (m = buffer.poll()) != null) {
                batch.add(m);
            }
            approxBufferSize = buffer.size();
            maybeResumeProducers();
            done.complete(null);
        });
        return done;
    }

    // --- Blocking views, for the synchronous receive() API. Block only the caller's thread. ---

    Message<T> take() throws PulsarClientException {
        try {
            return receiveAsync().get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new PulsarClientException("Receive interrupted", e);
        } catch (ExecutionException e) {
            throw unwrap(e);
        }
    }

    Message<T> poll(Duration timeout) throws PulsarClientException {
        try {
            return receiveAsync(timeout).get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new PulsarClientException("Receive interrupted", e);
        } catch (ExecutionException e) {
            throw unwrap(e);
        }
    }

    List<Message<T>> receiveMulti(int maxMessages, Duration timeout) throws PulsarClientException {
        try {

View on GitHub (pinned to 820761864e)