apache/seatunnel · warning
unable to rollback prepared transaction, xid={}
Error message
unable to rollback prepared transaction, xid={} What it means
JdbcExactlyOnceSinkWriter.rollbackPrepareXidQuietly attempts to roll back a previously prepared XA transaction (prepareXid) and, because this path is best-effort during abort, it only logs a WARN when the XA rollback fails instead of throwing. The prepared transaction may then remain in-doubt on the database until XA recovery resolves it. The actual underlying exception is attached to the log entry.
Source
Thrown at seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcExactlyOnceSinkWriter.java:259
long candidate = txIdHint;
if (candidate <= lastGeneratedTxId) {
checkState(lastGeneratedTxId != Long.MAX_VALUE, "tx id exhausted");
candidate = lastGeneratedTxId + 1;
}
lastGeneratedTxId = candidate;
return candidate;
}
private void rollbackPrepareXidQuietly() {
if (prepareXid == null || !xaFacade.isOpen()) {
return;
}
Xid xid = prepareXid;
try {
LOG.debug("rollback prepared transaction, xid={}", xid);
xaFacade.rollback(xid);
} catch (Exception e) {
LOG.warn("unable to rollback prepared transaction, xid={}", xid, e);
} finally {
prepareXid = null;
}
}
private void rollbackPrepareXidOrThrow(Exception beginTxException) {
if (prepareXid == null) {
return;
}
Xid xid = prepareXid;
if (!xaFacade.isOpen()) {
throw new JdbcConnectorException(
JdbcConnectorErrorCode.XA_OPERATION_FAILED,
String.format(
"unable to rollback prepared transaction because xaFacade is closed, xid=%s",
xid),
beginTxException);
}View on GitHub (pinned to cf67b549a7)
Solutions
- Inspect the attached exception 'e' in the log line to identify the XA error code (e.g. XAER_RMFAIL vs XAER_NOTA)
- Rely on XA recovery: on restart the sink recovers pending transactions via xaGroupOps.recoverAndRollback, so ensure the DB user has XA_RECOVER_ADMIN / SELECT on xa_recover and the xidGenerator config is unchanged
- Check DB connectivity and reconnect before retrying abort
- Manually resolve in-doubt transactions if recovery cannot (e.g. xa recover; xa rollback <xid> in MySQL/Oracle)
- Keep xid generation parameters (subtask index, job id) stable across restarts so recovery can find the prepared xids
Example fix
// before: swallowing without cleanup of in-doubt tx
} catch (Exception e) {
LOG.warn("unable to rollback prepared transaction, xid={}", xid, e);
}
// after: schedule recovery instead of silently dropping
} catch (Exception e) {
LOG.warn("unable to rollback prepared transaction, xid={}", xid, e);
xaGroupOps.recoverAndRollback(context, sinkcontext, xidGenerator, null);
} Defensive patterns
Strategy: retry
Validate before calling
// before abort, check the facade/connection is still usable
if (xaFacade != null) {
// verify DB reachable so rollback has a chance
java.sql.Connection probe = dataSource.getConnection();
probe.isValid(5);
probe.close();
} Try / catch
try {
xaFacade.rollback(xid);
} catch (XAException e) {
// XAER_NOTA (code -4): already rolled back/unknown — safe to ignore;
// otherwise ensure the job restarts so XA recovery sweeps the in-doubt xid
LOG.warn("rollback of {} failed, code={}", xid, e.errorCode, e);
} Prevention
- Enable keepalive/short socketTimeout so dead DB connections are detected early
- Never change xidGenerator or job/subtask identity config between restarts, or recovery cannot find prepared xids
- Grant the sink DB user recovery privileges so startup recovery can clean in-doubt transactions
- Monitor the database for in-doubt XA transactions after any abort
When it happens
Trigger: abortPrepare -> rollbackPrepareXidQuietly when xaFacade.rollback(xid) throws — e.g. connection to the database lost after prepare, the resource manager no longer knows the xid, XAER_RMFAIL, or the facade/connection is already closed.
Common situations: Task failure/abort during checkpoint after xa prepare; database restart between prepare and rollback; network partition to the DB; DBA killed the in-doubt transaction; connection pool reclaimed the XA connection.
Related errors
- begin next transaction failed, rollback prepared transaction
- rollback prepared transaction failed, try to recover pending
- recovery after rollback prepared transaction failure also fa
- CLASS_NOT_FOUND
- CONNECT_DATABASE_FAILED
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/33a7164f8b3e2db0.
Report an issue: GitHub.