{"record":{"id":"7c71935926c6e475","repo":"apache/seatunnel","slug":"cannot-fetch-from-another-split-no-split-remaini","errorCode":null,"errorMessage":"Cannot fetch from another split - no split remaining.","messagePattern":"Cannot fetch from another split - no split remaining\\.","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":161,"sourceCode":"            currentSplitId = null;\n            emittedFinishedSplitId = null;\n        }\n    }\n\n    private void checkNeedStopBinlogReader() {\n        // TODO Currently not supported\n    }\n\n    protected void checkSplitOrStartNext() throws IOException {\n        // the stream fetcher should keep alive\n        if (currentFetcher instanceof IncrementalSourceStreamFetcher) {\n            return;\n        }\n\n        if (canAssignNextSplit()) {\n            final SourceSplitBase nextSplit = splits.poll();\n            if (nextSplit == null) {\n                throw new IOException(\"Cannot fetch from another split - no split remaining.\");\n            }\n            currentSplitId = nextSplit.splitId();\n            emittedFinishedSplitId = null;\n\n            if (nextSplit.isSnapshotSplit()) {\n                if (currentFetcher == null) {\n                    final FetchTask.Context taskContext =\n                            dataSourceDialect.createFetchTaskContext(nextSplit, sourceConfig);\n                    currentFetcher = new IncrementalSourceScanFetcher(taskContext, subtaskId);\n                }\n            } else {\n                // point from snapshot split to incremental split\n                if (currentFetcher != null) {\n                    log.info(\n                            \"It's turn to read incremental split, close current snapshot fetcher.\");\n                    currentFetcher.close();\n                }\n                final FetchTask.Context taskContext =","sourceCodeStart":143,"sourceCodeEnd":179,"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#L143-L179","documentation":"checkSplitOrStartNext() pops the next split from the queued splits when it can assign a new one; the queue returned null/empty despite canAssignNextSplit() being true, which is an impossible/invalid internal state (no split remaining to fetch from). Thrown as IOException to fail the reader task.","triggerScenarios":"fetch() -> checkSplitOrStartNext(): canAssignNextSplit() returns true (e.g. currentSplitId is null and no finished-split is pending) but splits.poll() yields null — meaning the reader believes it should take a new split while none was delivered.","commonSituations":"Enumerator and reader state divergence after checkpoint restore; splits consumed but reader state (emittedFinishedSplitId/currentSplitId) not updated consistently; engine bug in split delivery order.","solutions":["Restart the job from the last successful checkpoint to resynchronize split state","Enable debug logging of handleSplitsChanges/checkSplitOrStartNext to confirm splits were actually sent to this reader","Verify the enumerator is alive and assigning splits (check for table-discovery or assignment errors upstream)","Upgrade SeaTunnel/connector version if this matches a known split-assignment race bug"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Before fetch: confirm a split is queued or a split is active\nif (canAssignNextSplit() && splits.isEmpty() && currentSplitId == null) {\n    LOG.warn(\"No split available; skipping fetch cycle instead of polling null\");\n    return;\n}","typeGuard":null,"tryCatchPattern":"try { checkSplitOrStartNext(); }\ncatch (IOException e) {\n  if (e.getMessage().contains(\"no split remaining\")) { restartFromLastCheckpoint(); }\n  else { throw e; }\n}","preventionTips":["Keep enumerator and reader in sync; restore from consistent checkpoints only","Log split assignment to detect delivery gaps early","Upgrade connector/engine if split-assignment races are known fixed upstream"],"tags":["cdc","state","split-assignment","internal-state"],"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"}