{"record":{"id":"5a52a1a07803601b","repo":"apache/seatunnel","slug":"begin-next-transaction-failed-rollback-prepared-t","errorCode":null,"errorMessage":"begin next transaction failed, rollback prepared transaction, xid={}","messagePattern":"begin next transaction failed, rollback prepared transaction, xid=(.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcExactlyOnceSinkWriter.java","lineNumber":279,"sourceCode":"            prepareXid = null;\n        }\n    }\n\n    private void rollbackPrepareXidOrThrow(Exception beginTxException) {\n        if (prepareXid == null) {\n            return;\n        }\n        Xid xid = prepareXid;\n        if (!xaFacade.isOpen()) {\n            throw new JdbcConnectorException(\n                    JdbcConnectorErrorCode.XA_OPERATION_FAILED,\n                    String.format(\n                            \"unable to rollback prepared transaction because xaFacade is closed, xid=%s\",\n                            xid),\n                    beginTxException);\n        }\n        try {\n            LOG.warn(\"begin next transaction failed, rollback prepared transaction, xid={}\", xid);\n            xaFacade.rollback(xid);\n            prepareXid = null;\n        } catch (Exception rollbackException) {\n            JdbcConnectorException rollbackFailure =\n                    new JdbcConnectorException(\n                            JdbcConnectorErrorCode.XA_OPERATION_FAILED,\n                            String.format(\n                                    \"failed to rollback prepared transaction after begin next transaction failure, xid=%s\",\n                                    xid),\n                            rollbackException);\n            rollbackFailure.addSuppressed(beginTxException);\n            tryRecoverPreparedTransactionsAfterRollbackFailure(xid, rollbackFailure);\n            throw rollbackFailure;\n        }\n    }\n\n    private void tryRecoverPreparedTransactionsAfterRollbackFailure(\n            Xid failedRollbackXid, JdbcConnectorException rollbackFailure) {","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcExactlyOnceSinkWriter.java#L261-L297","documentation":"Logged by JdbcExactlyOnceSinkWriter.rollbackPrepareXidOrThrow: a new XA transaction could not be started (beginTxException) while a previously prepared transaction existed, so the writer tries to roll back the prepared xid before failing. If this rollback also throws, a JdbcConnectorException (XA_OPERATION_FAILED) chain is built combining beginTx failure and rollback failure and subsequently thrown.","triggerScenarios":"prepareCommit attempts to begin the next XA transaction, the begin fails (connection lost, DB down, XAER_RMERR), and then xaFacade.rollback(prepared xid) on the old prepared transaction also throws — e.g. same broken connection, facade closed, or xid unknown to the resource manager.","commonSituations":"Database outage or failover in the middle of a checkpoint's prepareCommit; network partition; connection pool returned a dead connection to the XA facade; exceeding DB max prepared transactions; user lacks XA privileges after a grants change.","solutions":["Check the DB availability and network from the SeaTunnel worker node first — the root cause is in beginTxException","Review the chained JdbcConnectorException (beginTxException + rollbackFailure + suppressed recovery failure) for the original XA error code","Let the sink's recovery path run: after restart, recoverAndRollback resolves the in-doubt prepared transaction; ensure DB account has recovery privileges","Verify XA support is correctly configured for the dialect (driver, URL, xaDataSource class) and credentials still have XA permissions","If caused by a dead pooled connection, align pool keepalive/validation settings as with stale-connection issues"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// before relying on exactly-once, verify XA begin/prepare works and privileges exist\ntry (XAConnection xa = xaDs.getXAConnection(); XAResource r = xa.getXAResource()) {\n    Xid probe = new XidImpl();\n    r.start(probe, XAResource.TMNOFLAGS);\n    r.end(probe, XAResource.TMSUCCESS);\n    r.rollback(probe); // succeeds only if XA is usable\n}","typeGuard":null,"tryCatchPattern":"try {\n    prepareCommit();\n} catch (JdbcConnectorException e) {\n    // error code XA_OPERATION_FAILED chains beginTx + rollback failures\n    if (e.getErrorCode() == JdbcConnectorErrorCode.XA_OPERATION_FAILED) {\n        LOG.error(\"XA begin/rollback failed; restart job to trigger recovery\", e);\n    }\n}","preventionTips":["Monitor DB health before checkpoints; fail fast on network instability","Confirm XA grants and dialect XA support when setting up credentials","Keep the XA facade's underlying connection validated (test-on-borrow)","After the job fails, always run recovery — do not manually discard prepared xids blindly"],"tags":["jdbc","xa","distributed-transaction","prepare-commit","rollback-failure"],"backgroundTag":"xa-rollback-failed","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}