{"record":{"id":"fdc9ebde687b0d41","repo":"apache/seatunnel","slug":"skipping-checkpoint-transactions-that-are-absen","errorCode":null,"errorMessage":"Skipping {} checkpoint transactions that are absent from the XA recovery scan but precede the first still-prepared transaction: {}","messagePattern":"Skipping (.+?) checkpoint transactions that are absent from the XA recovery scan but precede the first still-prepared transaction: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcSinkAggregatedCommitter.java","lineNumber":234,"sourceCode":"                    checkpointXids);\n            return;\n        }\n        List<XidInfo> stillPrepared = new ArrayList<>();\n        for (int i = firstRecoveredIndex; i < checkpointXids.size(); i++) {\n            XidInfo xidInfo = checkpointXids.get(i);\n            if (!containsEquivalentXid(recoveredXids, xidInfo.getXid())) {\n                throw new JdbcConnectorException(\n                        CommonErrorCodeDeprecated.WRITER_OPERATION_FAILED,\n                        String.format(\n                                \"checkpoint transaction %s is absent from the XA recovery scan after still-prepared transactions in the same commit batch: %s\",\n                                xidInfo.getXid(), checkpointXids));\n            }\n            stillPrepared.add(xidInfo);\n        }\n        commitXidInfos(stillPrepared);\n        if (firstRecoveredIndex > 0) {\n            List<XidInfo> alreadyResolved = checkpointXids.subList(0, firstRecoveredIndex);\n            log.warn(\n                    \"Skipping {} checkpoint transactions that are absent from the XA recovery scan but precede the first still-prepared transaction: {}\",\n                    alreadyResolved.size(),\n                    alreadyResolved);\n        }\n    }\n\n    /**\n     * Retries the recovery scan with the same bounded budget as XA commit so transient RM outages\n     * do not fail restore immediately.\n     *\n     * @return canonical values returned by the recovery scan\n     */\n    private Set<XidKey> recoverCheckpointTransactions() {\n        int maxCommitAttempts = jdbcSinkConfig.getJdbcConnectionConfig().getMaxCommitAttempts();\n        XaFacade.TransientXaException lastTransientFailure = null;\n        for (int attempt = 1; attempt <= Math.max(1, maxCommitAttempts); attempt++) {\n            try {\n                return normalizeXids(xaFacade.recover());","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcSinkAggregatedCommitter.java#L216-L252","documentation":"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.","triggerScenarios":"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.","commonSituations":"Crash between XA commits of an ordered batch; partial resolution by a prior restore; checking recovery on a replica with incomplete XA visibility.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"Set<String> recovered = xaRecoverKeys();\nList<XidInfo> unresolved = checkpointXids.stream()\n    .filter(x -> recovered.contains(keyOf(x)))\n    .collect(Collectors.toList());","typeGuard":null,"tryCatchPattern":"try {\n    restoreCommit(checkpointXids);\n} catch (XaFacade.TransientXaException e) {\n    log.warn(\"Transient recovery failure; re-run restore\", e);\n}","preventionTips":["Preserve checkpoint batch ordering across restores","Ensure recovery scan covers all prepared Xids (same user/DB)","Design downstream for idempotent commits"],"tags":["xa","recovery","checkpoint"],"backgroundTag":"invalid-state-transition","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}