{"record":{"id":"f7b5e8399eb3f95f","repo":"apache/pulsar","slug":"wraps-abort-failure-cause-message","errorCode":null,"errorMessage":"(wraps abort failure cause message)","messagePattern":"\\(wraps abort failure cause message\\)","errorType":"exception","errorClass":"PulsarClientException","httpStatus":null,"severity":"error","filePath":"pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/TransactionV5.java","lineNumber":67,"sourceCode":"        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new PulsarClientException(\"Commit interrupted\", e);\n        } catch (ExecutionException e) {\n            Throwable cause = e.getCause() != null ? e.getCause() : e;\n            throw new PulsarClientException(cause.getMessage(), cause);\n        }\n    }\n\n    @Override\n    public void abort() throws PulsarClientException {\n        try {\n            v4Transaction.abort().get();\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new PulsarClientException(\"Abort interrupted\", e);\n        } catch (ExecutionException e) {\n            Throwable cause = e.getCause() != null ? e.getCause() : e;\n            throw new PulsarClientException(cause.getMessage(), cause);\n        }\n    }\n\n    @Override\n    public AsyncTransaction async() {\n        return asyncView;\n    }\n\n    @Override\n    public State state() {\n        return switch (v4Transaction.getState()) {\n            case OPEN -> State.OPEN;\n            case COMMITTING -> State.COMMITTING;\n            case ABORTING -> State.ABORTING;\n            case COMMITTED -> State.COMMITTED;\n            case ABORTED -> State.ABORTED;\n            case ERROR -> State.ERROR;\n            case TIME_OUT -> State.TIMED_OUT;","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/TransactionV5.java#L49-L85","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ntxn.abort(); // throws with cause message\n// after\ntry {\n    txn.abort();\n} catch (PulsarClientException e) {\n    log.warn(\"abort failed; transaction state should be checked\", e);\n    // treat as rolled-back if cause indicates transaction already aborted/expired\n}","handlingStrategy":"try-catch","validationCode":"if (txn == null) throw new IllegalStateException(\"transaction already closed; nothing to abort\");\nif (committed.get()) throw new IllegalStateException(\"cannot abort after commit initiated\");","typeGuard":"static boolean isAlreadyAborted(Throwable t) {\n    Throwable c = t;\n    while (c != null) {\n        String m = c.getMessage();\n        if (m != null && (m.contains(\"already\") || m.contains(\"Invalid\"))) return true;\n        c = c.getCause();\n    }\n    return false;\n}","tryCatchPattern":"try {\n    txn.abort();\n} catch (PulsarClientException e) {\n    log.warn(\"abort failed: {}\", e.getCause() != null ? e.getCause().getMessage() : e.getMessage(), e);\n}","preventionTips":["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"],"tags":["transaction","abort","pulsar-client","wrapped-exception"],"backgroundTag":"transaction-abort-failed","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}