apache/pulsar · error · PulsarClientException
(wraps abort failure cause message)
Error message
(wraps abort failure cause message)
What it means
TransactionV5.abort() blocks on the v4 transaction's abort future; when it completes with ExecutionException, the cause is extracted (or the ExecutionException itself if cause is null) and rethrown as a PulsarClientException whose message is the cause's message. This surfaces the actual reason the abort failed, e.g. broker rejection or coordinator unavailability.
Source
Thrown at pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/TransactionV5.java:67
} 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;
case ABORTED -> State.ABORTED;
case ERROR -> State.ERROR;
case TIME_OUT -> State.TIMED_OUT;View on GitHub (pinned to 820761864e)
Solutions
- Inspect getCause() for the broker's precise abort failure.
- Don't abort after commit has been initiated — serialize commit/abort with single-thread ownership.
- Check coordinator/broker connectivity; a timed-out transaction is already aborted server-side, so treat timeout causes as rollback-complete.
- Retry with a fresh transaction for work that must be redone.
Example fix
// before
txn.abort(); // throws with cause message
// after
try {
txn.abort();
} catch (PulsarClientException e) {
log.warn("abort failed; transaction state should be checked", e);
// treat as rolled-back if cause indicates transaction already aborted/expired
} Defensive patterns
Strategy: try-catch
Validate before calling
if (txn == null) throw new IllegalStateException("transaction already closed; nothing to abort");
if (committed.get()) throw new IllegalStateException("cannot abort after commit initiated"); Type guard
static boolean isAlreadyAborted(Throwable t) {
Throwable c = t;
while (c != null) {
String m = c.getMessage();
if (m != null && (m.contains("already") || m.contains("Invalid"))) return true;
c = c.getCause();
}
return false;
} Try / catch
try {
txn.abort();
} catch (PulsarClientException e) {
log.warn("abort failed: {}", e.getCause() != null ? e.getCause().getMessage() : e.getMessage(), e);
} Prevention
- Never interleave commit and abort on the same transaction
- Track transaction lifecycle state locally before calling abort
- Check coordinator connectivity when aborts fail repeatedly
- Treat expired transactions as already aborted server-side
When it happens
Trigger: Calling abort() when the underlying v4 abort future fails — transaction already committed, coordinator unreachable, transaction timed out and reaped, or broker-side error while rolling back pending acknowledgements/sends.
Common situations: Aborting a transaction that already timed out on the broker; network partitions to the transaction coordinator; abort racing with a concurrent commit from another thread.
Related errors
- (wraps commit failure cause message)
- (wraps underlying failure cause)
- (wraps v4 producer error message)
- (wraps subscribeAsync failure cause)
- Abort interrupted
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/f7b5e8399eb3f95f.
Report an issue: GitHub.