apache/pulsar · error · org.apache.pulsar.client.impl.v5.PulsarClientException

Close interrupted

Error message

Close interrupted

What it means

MultiTopicStreamConsumer.close was interrupted while waiting for the async close to complete; the interrupt is re-set on the thread and surfaced as a PulsarClientException so callers know close did not finish normally.

Source

Thrown at pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/MultiTopicStreamConsumer.java:359

                // detached it and no longer ack removed topics, so skip its slice.
                continue;
            }
            action.accept(state.consumer, entry.getValue());
        }
    }

    @Override
    public AsyncStreamConsumer<T> async() {
        return asyncView;
    }

    @Override
    public void close() throws PulsarClientException {
        try {
            closeAsync().get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new PulsarClientException("Close interrupted", e);
        } catch (ExecutionException e) {
            throw new PulsarClientException(e.getCause());
        }
    }

    CompletableFuture<Void> closeAsync() {
        if (closed) {
            return CompletableFuture.completedFuture(null);
        }
        closed = true;
        watcher.close();
        mux.close();
        // Cancel pending retries for topics that never finished subscribing (they're not in
        // perTopic, so the closeTopic loop below wouldn't reach them).
        retryTimeouts.values().forEach(Timeout::cancel);
        retryTimeouts.clear();
        List<CompletableFuture<Void>> closes = new ArrayList<>();
        for (var topic : new HashSet<>(perTopic.keySet())) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Avoid interrupting the closing thread; use closeAsync() for non-blocking close
  2. Retry close if resources remain after the interrupt

Example fix

// before
streamConsumer.close(); // blocking, interruptible
// after
streamConsumer.closeAsync()
    .get(30, TimeUnit.SECONDS); // or handle InterruptedException explicitly
Defensive patterns

Strategy: try-catch

Try / catch

try { streamConsumer.close(); } catch (PulsarClientException e) { /* check interruption state */ }

Prevention

When it happens

Trigger: Thread interruption during close(), typically from executor shutdownNow(), task cancellation, or shutdown hooks.

Common situations: App teardown racing consumer close; watchdog threads interrupting slow closes during broker unavailability.

Related errors


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