apache/pulsar · error · PulsarClientException
(wraps commit failure cause message)
Error message
(wraps commit failure cause message)
What it means
TransactionV5.commit() blocks on the v4 transaction's commit future; when that future completes with ExecutionException, the cause is extracted (falling back to the ExecutionException itself if the cause is null) and rethrown as a PulsarClientException whose message is the underlying cause's message. This error therefore reports the broker/client's real reason the commit failed.
Source
Thrown at pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/TransactionV5.java:54
TransactionV5(org.apache.pulsar.client.api.transaction.Transaction v4Transaction) {
this.v4Transaction = v4Transaction;
this.asyncView = new AsyncView();
}
org.apache.pulsar.client.api.transaction.Transaction v4Transaction() {
return v4Transaction;
}
@Override
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() {View on GitHub (pinned to 820761864e)
Solutions
- Read the wrapped cause (getCause()) for the broker's actual rejection reason.
- Commit within the transaction timeout — increase transactionTimeoutSeconds if operations take long.
- Ensure only one thread commits/aborts the transaction; guard with ownership or serialization.
- Check broker availability and transaction coordinator health; retry with a new transaction if the old one is definitively failed.
Example fix
// before
txn.commit(); // may throw with opaque broker message
// after
try {
txn.commit();
} catch (PulsarClientException e) {
Throwable root = e.getCause() != null ? e.getCause() : e;
if (root instanceof TransactionInvalidException) {
startNewTransactionAndRetry();
} else {
throw e;
}
} Defensive patterns
Strategy: try-catch
Validate before calling
if (txn == null || !txn.isOpen()) throw new IllegalStateException("transaction not open; cannot commit");
if (System.currentTimeMillis() - txnStartMillis > txnTimeoutMillis) log.warn("committing after timeout risk"); Type guard
static boolean isCommitRejected(Throwable t) {
Throwable c = t;
while (c != null) { if (c.getMessage() != null && c.getMessage().contains("Transaction")) return true; c = c.getCause(); }
return false;
} Try / catch
try {
txn.commit();
} catch (PulsarClientException e) {
Throwable cause = e.getCause() != null ? e.getCause() : e;
log.error("commit failed: {}", cause.getMessage(), cause);
} Prevention
- Commit well within the configured transaction timeout
- Single-thread ownership of commit/abort per transaction
- Log the full cause chain, not just the wrapper message
- Monitor broker transaction-coordinator health
When it happens
Trigger: Calling commit() when the underlying v4 commit future fails — broker rejected the commit, transaction timed out or was already aborted, coordinator unavailable, or the producer/consumer attached to the transaction errored.
Common situations: Transaction timeout exceeded (committing after the TTL); transaction coordinator restarted or unavailable; committing a transaction that another thread already aborted; broker-side authorization or ledger failures.
Related errors
- (wraps abort failure cause message)
- (wraps underlying failure cause)
- (wraps v4 producer error message)
- (wraps subscribeAsync failure cause)
- Error creating client for HealthChecker
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/7f58c06f65977104.
Report an issue: GitHub.