apache/seatunnel · warning
rollback prepared transaction failed, try to recover pending
Error message
rollback prepared transaction failed, try to recover pending transactions for current subtask, xid={} What it means
Logged by tryRecoverPreparedTransactionsAfterRollbackFailure: when rolling back a prepared XA transaction fails, the writer attempts a best-effort XA recovery (xaGroupOps.recoverAndRollback) for the current subtask to list and roll back all in-doubt transactions. This WARN indicates the direct rollback failed and the recovery fallback is being attempted; it is not itself the failure.
Source
Thrown at seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcExactlyOnceSinkWriter.java:299
prepareXid = null;
} catch (Exception rollbackException) {
JdbcConnectorException rollbackFailure =
new JdbcConnectorException(
JdbcConnectorErrorCode.XA_OPERATION_FAILED,
String.format(
"failed to rollback prepared transaction after begin next transaction failure, xid=%s",
xid),
rollbackException);
rollbackFailure.addSuppressed(beginTxException);
tryRecoverPreparedTransactionsAfterRollbackFailure(xid, rollbackFailure);
throw rollbackFailure;
}
}
private void tryRecoverPreparedTransactionsAfterRollbackFailure(
Xid failedRollbackXid, JdbcConnectorException rollbackFailure) {
try {
LOG.warn(
"rollback prepared transaction failed, try to recover pending transactions for current subtask, xid={}",
failedRollbackXid);
xaGroupOps.recoverAndRollback(context, sinkcontext, xidGenerator, null);
} catch (Exception recoveryException) {
LOG.warn(
"recovery after rollback prepared transaction failure also failed, xid={}",
failedRollbackXid,
recoveryException);
rollbackFailure.addSuppressed(recoveryException);
}
}
private void failAndRollbackCurrentXidQuietly() {
if (currentXid == null || !xaFacade.isOpen()) {
return;
}
Xid xid = currentXid;
try {View on GitHub (pinned to cf67b549a7)
Solutions
- Wait for/inspect the follow-up log: if recovery succeeds the pending transactions are cleaned up and no action is needed
- If recovery also fails (next WARN), fix the underlying DB connectivity and restart the job so recovery runs at startup
- Ensure the DB user has XA recovery privileges (XA_RECOVER_ADMIN on MySQL 8, or appropriate Oracle/PG settings) so recoverAndRollback can list xids
- Keep job/subtask identity and xidGenerator settings consistent across restarts so recovery can match the prepared xids
- Manually inspect in-doubt transactions (xa recover / DBA_RECOVERABLE transactions) and roll them back if automated recovery cannot
Defensive patterns
Strategy: try-catch
Validate before calling
// ensure recovery is possible before it is needed // DB user must be allowed to list in-doubt transactions -- MySQL: SHOW GRANTS must include XA_RECOVER_ADMIN -- psql: SELECT gid FROM pg_prepared_xacts; should be permitted
Try / catch
// this log is itself the catch/fallback path; guard the caller
try {
prepareCommit();
} catch (Exception e) {
LOG.warn("prepareCommit failed; recovery will run on restart", e);
// let the framework abort so tryRecoverPreparedTransactionsAfterRollbackFailure executes
} Prevention
- Grant XA recovery privileges to the connector's DB account
- Keep xid generation stable across restarts (same job id/subtask mapping)
- Test failover: kill the DB mid-checkpoint in a staging run and confirm recovery cleans prepared xids
- Avoid tight DB firewall/NAT idle cutoffs on the XA connection
When it happens
Trigger: Called from rollbackPrepareXidOrThrow after xaFacade.rollback(failedRollbackXid) throws during prepareCommit; any XA error on the prepared xid (XAER_RMFAIL, connection lost, facade closed) routes here.
Common situations: DB restart/failover between prepare and rollback; network partition; resource manager lost the transaction; driver-level XA errors on flaky connections.
Related errors
- recovery after rollback prepared transaction failure also fa
- rollback {} recovered transactions
- unable to rollback prepared transaction, xid={}
- begin next transaction failed, rollback prepared transaction
- CLASS_NOT_FOUND
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/75b303381551dcc0.
Report an issue: GitHub.