apache/pulsar · warning · PulsarClientException

Abort interrupted

Error message

Abort interrupted

What it means

TransactionV5.abort() blocks on the underlying v4 transaction's abort future. If the waiting thread is interrupted during that wait, the interrupt flag is restored and a PulsarClientException with the fixed message "Abort interrupted" is thrown. The abort may still have completed server-side; only the caller's wait was cancelled.

Source

Thrown at pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/TransactionV5.java:64

    public void commit() throws PulsarClientException {
        try {
            v4Transaction.commit().get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new PulsarClientException("Commit interrupted", e);
        } catch (ExecutionException e) {
            Throwable cause = e.getCause() != null ? e.getCause() : e;
            throw new PulsarClientException(cause.getMessage(), cause);
        }
    }

    @Override
    public void abort() throws PulsarClientException {
        try {
            v4Transaction.abort().get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new PulsarClientException("Abort interrupted", e);
        } catch (ExecutionException e) {
            Throwable cause = e.getCause() != null ? e.getCause() : e;
            throw new PulsarClientException(cause.getMessage(), cause);
        }
    }

    @Override
    public AsyncTransaction async() {
        return asyncView;
    }

    @Override
    public State state() {
        return switch (v4Transaction.getState()) {
            case OPEN -> State.OPEN;
            case COMMITTING -> State.COMMITTING;
            case ABORTING -> State.ABORTING;
            case COMMITTED -> State.COMMITTED;

View on GitHub (pinned to 820761864e)

Solutions

  1. Prefer asyncView.async().abortAsync() to avoid blocking waits that can be interrupted.
  2. Ensure threads performing aborts are not interrupted during shutdown; drain pending aborts before terminating executors.
  3. After an interrupted abort, verify the transaction state on the coordinator; it may already be aborted — do not blindly retry commit.

Example fix

// before
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    throw new PulsarClientException("Abort interrupted", e);
}
// after
// caller-side: avoid interrupting aborts
Executors.newSingleThreadExecutor().submit(() -> {
    try { txn.abort(); } catch (PulsarClientException e) { log.warn("abort issue", e); }
});
Defensive patterns

Strategy: try-catch

Validate before calling

if (Thread.currentThread().isInterrupted()) {
    log.warn("thread interrupted before abort; transaction left to TTL expiry");
    return;
}

Try / catch

try {
    txn.abort();
} catch (PulsarClientException e) {
    if ("Abort interrupted".equals(e.getMessage())) {
        // abort may have completed; check state before retry
    }
}

Prevention

When it happens

Trigger: Calling abort() on a thread interrupted while blocked in v4Transaction.abort().get() — executor shutdown, cancellation, or an explicit interrupt from another thread.

Common situations: Rollback during application shutdown when the worker thread is interrupted; timeout watchdogs interrupting threads stuck on abort; test frameworks cancelling blocked cleanup threads.

Related errors


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