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

  1. Treat as expected when the missing Xids were committed before the crash
  2. Ensure the same recovery user/database is scanned so no prepared Xids are hidden
  3. 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

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


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