apache/seatunnel · warning
Skipping {} checkpoint transactions that are absent from the
Error message
Skipping {} checkpoint transactions that are absent from the XA recovery scan but precede the first still-prepared transaction: {} What it means
In replayRecoveredCheckpoint, checkpoint Xids that appear BEFORE the first still-prepared Xid in the checkpoint batch are absent from the XA recovery scan. Since the batch is ordered, these earlier transactions are presumed already committed, so they are skipped and a WARN with count and list is logged.
Source
Thrown at seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcSinkAggregatedCommitter.java:234
checkpointXids);
return;
}
List<XidInfo> stillPrepared = new ArrayList<>();
for (int i = firstRecoveredIndex; i < checkpointXids.size(); i++) {
XidInfo xidInfo = checkpointXids.get(i);
if (!containsEquivalentXid(recoveredXids, xidInfo.getXid())) {
throw new JdbcConnectorException(
CommonErrorCodeDeprecated.WRITER_OPERATION_FAILED,
String.format(
"checkpoint transaction %s is absent from the XA recovery scan after still-prepared transactions in the same commit batch: %s",
xidInfo.getXid(), checkpointXids));
}
stillPrepared.add(xidInfo);
}
commitXidInfos(stillPrepared);
if (firstRecoveredIndex > 0) {
List<XidInfo> alreadyResolved = checkpointXids.subList(0, firstRecoveredIndex);
log.warn(
"Skipping {} checkpoint transactions that are absent from the XA recovery scan but precede the first still-prepared transaction: {}",
alreadyResolved.size(),
alreadyResolved);
}
}
/**
* Retries the recovery scan with the same bounded budget as XA commit so transient RM outages
* do not fail restore immediately.
*
* @return canonical values returned by the recovery scan
*/
private Set<XidKey> recoverCheckpointTransactions() {
int maxCommitAttempts = jdbcSinkConfig.getJdbcConnectionConfig().getMaxCommitAttempts();
XaFacade.TransientXaException lastTransientFailure = null;
for (int attempt = 1; attempt <= Math.max(1, maxCommitAttempts); attempt++) {
try {
return normalizeXids(xaFacade.recover());View on GitHub (pinned to cf67b549a7)
Solutions
- Treat as expected when the missing Xids were committed before the crash
- Ensure the same recovery user/database is scanned so no prepared Xids are hidden
- Persist commit bookkeeping (or enable idempotent sink) to safely confirm resolution
Defensive patterns
Strategy: try-catch
Validate before calling
Set<String> recovered = xaRecoverKeys();
List<XidInfo> unresolved = checkpointXids.stream()
.filter(x -> recovered.contains(keyOf(x)))
.collect(Collectors.toList()); Try / catch
try {
restoreCommit(checkpointXids);
} catch (XaFacade.TransientXaException e) {
log.warn("Transient recovery failure; re-run restore", e);
} Prevention
- Preserve checkpoint batch ordering across restores
- Ensure recovery scan covers all prepared Xids (same user/DB)
- Design downstream for idempotent commits
When it happens
Trigger: restoreCommit -> replayRecoveredCheckpoint after crash/failover when xa_recover shows only later transactions of a checkpoint batch still prepared — the earlier ones were committed before the crash.
Common situations: Crash between XA commits of an ordered batch; partial resolution by a prior restore; checking recovery on a replica with incomplete XA visibility.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Skipping checkpoint batch because none of its transactions r
- Failed to get all checkpoints for job ${jobId}
- ${ExceptionUtils.getMessage(e)}
- No checkpoint found, job(${jobId}), pipeline(${pipelineId}),
- rollback {} recovered transactions
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/fdc9ebde687b0d41.
Report an issue: GitHub.