apache/seatunnel · error · JdbcConnectorException
XA_OPERATION_FAILED
XA_OPERATION_FAILED
Error message
unable to start xa transaction, xid=%s
What it means
beginTx() generates an Xid and calls xaFacade.start(currentXid) to begin an XA transaction; if start fails, the error carries the specific xid and code XA_OPERATION_FAILED. This happens on every new transaction started by the exactly-once writer (initial open and each prepareCommit), so it typically means the database refused the XA START.
Source
Thrown at seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcExactlyOnceSinkWriter.java:233
e);
} finally {
outputFormat.close();
xidGenerator.close();
currentXid = null;
prepareXid = null;
}
}
private void beginTx(long txIdHint) throws IOException {
checkState(currentXid == null, "currentXid not null");
long txId = nextTxId(txIdHint);
currentXid = xidGenerator.generateXid(context, sinkcontext, txId);
try {
xaFacade.start(currentXid);
} catch (Exception e) {
Xid xid = currentXid;
currentXid = null;
throw new JdbcConnectorException(
JdbcConnectorErrorCode.XA_OPERATION_FAILED,
String.format("unable to start xa transaction, xid=%s", xid),
e);
}
}
private long nextTxId(long txIdHint) {
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()) {View on GitHub (pinned to cf67b549a7)
Solutions
- Read the xid in the message and the cause: XAER_RMFAIL => reconnectivity issue; XAER_DUPID => xid collision
- Fix network/keepalive settings so the connection survives between checkpoints (e.g. TCP keepalive, connection pool validation)
- Ensure the XidGenerator produces unique xids per job/restart (check job id/seed configuration)
- Confirm the DB supports XA and max_prepared_transactions (PostgreSQL) is > 0
Example fix
// before xaFacade.start(currentXid) // fails: connection idle-dead after long checkpoint interval // after jdbc_url += "?tcpKeepAlive=true&autoReconnect=false" // and reduce checkpoint interval
Defensive patterns
Strategy: retry
Validate before calling
// verify XA start capability
try (XAConnection xa = xaDs.getXAConnection(); XAResource r = xa.getXAResource()) {
Xid test = new XidImpl(); r.start(test, XAResource.TMNOFLAGS); r.end(test, XAResource.TMSUCCESS); r.forget(test);
} Try / catch
catch (JdbcConnectorException e) { if (String.valueOf(e.getCause()).contains("XAER_DUPID")) fixXidGenerator(); else retryWithBackoff(); } Prevention
- Use unique xids per job run (configure distinct job id / xid prefix)
- Keep checkpoint intervals shorter than connection idle timeouts
- Enable TCP keepalive on the JDBC URL
- Confirm the DB supports XA and two-phase commit
When it happens
Trigger: beginTx is invoked by tryOpen (first transaction) and prepareCommit (each checkpoint interval); xaFacade.start fails when the underlying connection cannot start the XA transaction (connection dead, DB rejecting XA, duplicate xid).
Common situations: Connection killed by idle timeout between checkpoints; MySQL 'XAER_DUPID' from xid collision (weak xidGenerator across restarted jobs); database XA unsupported or misconfigured; DB outage at checkpoint time.
Related errors
- COMMON_WRITER_OPERATION_FAILED
- COMMON_WRITER_OPERATION_FAILED
- XA_OPERATION_FAILED
- formatErrorMessage(action, xid, errorCode, errorMessage)
- Exactly once is enabled, but not found primary key or unique
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/d8a225d33250348a.
Report an issue: GitHub.