apache/seatunnel · warning

Skipping checkpoint batch because none of its transactions r

Error message

Skipping checkpoint batch because none of its transactions remain in the XA recovery scan; treating it as already resolved: {}

What it means

During restoreCommit, JdbcSinkAggregatedCommitter.replayRecoveredCheckpoint() replays checkpointed XA transactions against the set of transactions still found in the database's XA recovery scan (xa_recover). If NONE of the checkpoint's XIDs appear in the recovery scan, the code assumes they were already committed/resolved and skips the batch, logging this WARN.

Source

Thrown at seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcSinkAggregatedCommitter.java:214

        }
        return normalized;
    }

    /**
     * Replays one restored checkpoint using the recovery scan as evidence for which transactions
     * can still be committed safely.
     *
     * @param checkpointXids checkpoint-owned prepared transactions in original commit order
     * @param recoveredXids canonical values returned by the resource manager recovery scan
     */
    private void replayRecoveredCheckpoint(
            List<XidInfo> checkpointXids, Set<XidKey> recoveredXids) {
        if (checkpointXids.isEmpty()) {
            return;
        }
        int firstRecoveredIndex = findFirstRecoveredIndex(checkpointXids, recoveredXids);
        if (firstRecoveredIndex < 0) {
            log.warn(
                    "Skipping checkpoint batch because none of its transactions remain in the XA recovery scan; treating it as already resolved: {}",
                    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) {

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Verify the recovery connection uses the same user/DB so xa_recover returns the transactions
  2. Check whether an earlier recovery pass already committed these Xids (expected, benign)
  3. If Xids are being purged prematurely, extend the DB's orphan-transaction retention / max_commit_timeout
  4. Inspect the DB for lost XA records and rely on downstream idempotency
Defensive patterns

Strategy: try-catch

Validate before calling

// before restore, list what recovery sees
Set<String> recovered = xaFacade.recover().stream()
    .map(x -> new String(x.getGlobalTransactionId(), UTF_8))
    .collect(Collectors.toSet());
checkpointXids.forEach(x -> {
    if (!recovered.contains(keyOf(x)))
        log.info("Xid {} not in recovery scan; presumed resolved", x);
});

Try / catch

try {
    committer.restoreCommit(checkpointXids);
} catch (TransientXaException e) {
    log.warn("Recovery scan failed; retry with backoff", e);
}

Prevention

When it happens

Trigger: Restoring a job from checkpoint whose checkpointed Xids are absent from xa_recover — e.g. transactions were resolved by a previous recovery run, the XA record expired/was purged, or the recovery scan hits a different user/database.

Common situations: Job restarted after crash; database cleanup jobs purging orphaned XA transactions; connecting with credentials lacking rights to see other users' XIDs; max_retry_timeout exceeded and externally committed.

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


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/705b8cf994e4d2e7. Report an issue: GitHub.