apache/seatunnel · error · java.lang.IllegalStateException

The update before event at for table was not followed by a

Error message

The update before event at  for table  was not followed by after event.

What it means

While merging DB2 change-table result sets in LSN order, an UPDATE_BEFORE event must be immediately followed by its matching UPDATE_AFTER event. If the next row is missing or is not an UPDATE_AFTER, the merged stream is corrupt and the task throws this IllegalStateException (the message interpolates change position and table id, which may render with gaps).

Source

Thrown at seatunnel-connectors-v2/connector-cdc/connector-cdc-db2/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/db2/source/reader/fetch/transactionlog/Db2TransactionLogFetchTask.java:330

                if (!schemaChangeCheckpoints.isEmpty()
                        && tableWithSmallestLsn
                                        .getChangePosition()
                                        .getCommitLsn()
                                        .compareTo(schemaChangeCheckpoints.peek().getStopLsn())
                                >= 0) {
                    migrateTable(partition, offsetContext, schemaChangeCheckpoints);
                }

                TableId tableId = tableWithSmallestLsn.getChangeTable().getSourceTableId();
                int operation = tableWithSmallestLsn.getOperation();
                Object[] data = tableWithSmallestLsn.getData();

                int eventCount = 1;
                if (operation == Db2ChangeRecordEmitter.OP_UPDATE_BEFORE) {
                    if (!tableWithSmallestLsn.next()
                            || tableWithSmallestLsn.getOperation()
                                    != Db2ChangeRecordEmitter.OP_UPDATE_AFTER) {
                        throw new IllegalStateException(
                                "The update before event at "
                                        + tableWithSmallestLsn.getChangePosition()
                                        + " for table "
                                        + tableId
                                        + " was not followed by after event.");
                    }
                    eventCount = 2;
                }
                Object[] dataNext =
                        operation == Db2ChangeRecordEmitter.OP_UPDATE_BEFORE
                                ? tableWithSmallestLsn.getData()
                                : null;

                TxLogPosition currentPosition = tableWithSmallestLsn.getChangePosition();
                offsetContext.setChangePosition(currentPosition, eventCount);
                offsetContext.event(
                        tableId, metadataConnection.timestampOfLsn(currentPosition.getCommitLsn()));

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Increase DB2 change-table retention so both halves of update pairs survive the read
  2. Verify the capture instance is intact and restart the streaming task from a clean checkpoint
  3. Check for jobs purging change tables concurrently with the connector's reads
  4. Retry from the last checkpoint after confirming change-table consistency
Defensive patterns

Strategy: retry

Validate before calling

// ensure change-table retention exceeds expected streaming duration
-- check DB2 CDC retention settings before long jobs

Try / catch

try { runPipeline(); } catch (IllegalStateException e) { if (e.getMessage().contains("was not followed by after event")) { verifyChangeTables(); restartFromCheckpoint(); } }

Prevention

When it happens

Trigger: readChangeTableResultSets encounters a change-table row with operation OP_UPDATE_BEFORE whose successor row is absent or has a different operation — e.g. missing change-table rows, expired change-table retention deleting one half of the pair, or concurrent modification during reads.

Common situations: Change-data-capture retention window too small so old rows get purged mid-read; capture instance re-created while streaming; DB2 CDC (SQL Server-style change tables) inconsistency; very high update volume during startup.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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