{"record":{"id":"1bc00db3580f995e","repo":"apache/seatunnel","slug":"invalid-state-currentsplitid-is-null-when-emittin","errorCode":null,"errorMessage":"Invalid state: currentSplitId is null when emitting records. emittedFinishedSplitId=%s, currentFetcher=%s, isFinished=%s","messagePattern":"Invalid state: currentSplitId is null when emitting records\\. emittedFinishedSplitId=(.+?), currentFetcher=(.+?), isFinished=(.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"critical","filePath":"seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/base/source/reader/IncrementalSourceSplitReader.java","lineNumber":106,"sourceCode":"        }\n        Iterator<SourceRecords> dataIt = null;\n        try {\n            dataIt = currentFetcher.pollSplitRecords();\n        } catch (InterruptedException | SeaTunnelException e) {\n            log.warn(\"fetch data failed.\", e);\n            throw new IOException(e);\n        }\n        if (dataIt == null) {\n            return finishedSnapshotSplit();\n        }\n        if (currentSplitId == null) {\n            log.warn(\n                    \"Invalid state: currentSplitId is null when emitting records. \"\n                            + \"emittedFinishedSplitId={}, currentFetcher={}, isFinished={}\",\n                    emittedFinishedSplitId,\n                    currentFetcher != null ? currentFetcher.getClass().getSimpleName() : \"null\",\n                    currentFetcher != null && currentFetcher.isFinished());\n            throw new IOException(\n                    String.format(\n                            \"Invalid state: currentSplitId is null when emitting records. \"\n                                    + \"emittedFinishedSplitId=%s, currentFetcher=%s, isFinished=%s\",\n                            emittedFinishedSplitId,\n                            currentFetcher != null\n                                    ? currentFetcher.getClass().getSimpleName()\n                                    : \"null\",\n                            currentFetcher != null && currentFetcher.isFinished()));\n        }\n        return ChangeEventRecords.forRecords(currentSplitId, dataIt);\n    }\n\n    @Override\n    public void handleSplitsChanges(SplitsChange<SourceSplitBase> splitsChanges) {\n        if (!(splitsChanges instanceof SplitsAddition)) {\n            throw new UnsupportedOperationException(\n                    String.format(\n                            \"The SplitChange type of %s is not supported.\",","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/base/source/reader/IncrementalSourceSplitReader.java#L88-L124","documentation":"IncrementalSourceSplitReader.fetch() encountered a state where it must emit records but currentSplitId is null — meaning no split is currently assigned to this reader. This indicates an internal coordination bug or race in split assignment/handover between the enumerator and reader, so it throws IOException to fail the task rather than silently emitting to an unknown split.","triggerScenarios":"fetch() -> getRecords() finds currentSplitId == null while records must be emitted; happens after a split finished and was acknowledged but the next split wasn't assigned yet, or on restore when split state and reader state diverged.","commonSituations":"Checkpoint/restore state corruption or version mismatch; race between handleSplitsChanges and fetch; a bug triggered by rapid split handover (many tiny snapshot splits); engine restart mid-split-transition.","solutions":["Restart the job from the last successful checkpoint/savepoint to realign enumerator and reader state","Reproduce with debug logging on split assignment (log.debug \"Handling split change\") to see whether splits were delivered","Check for reported connector/engine bugs around split handover and upgrade SeaTunnel if fixed upstream","Reduce checkpoint frequency of split state changes or reduce split count per table to narrow the race window"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"boolean hasAssignedSplit(IncrementalSourceSplitReader r) { return r != null && r.getCurrentSplitId() != null; }","tryCatchPattern":"try { records = reader.fetch(); }\ncatch (IOException e) {\n  if (e.getMessage().contains(\"currentSplitId is null\")) {\n    restartFromLastCheckpoint(); // realign enumerator/reader state\n  } else { throw e; }\n}","preventionTips":["Restore only from checkpoints created by the same connector version","Avoid extremely small snapshot splits that increase handover races","Keep engine and connector versions aligned"],"tags":["cdc","state","internal-state","split-reader"],"backgroundTag":"internal-invariant-violation","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"}