apache/seatunnel · critical · IOException
Cannot fetch from another split - no split remaining.
Error message
Cannot fetch from another split - no split remaining.
What it means
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.
Source
Thrown at seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/base/source/reader/IncrementalSourceSplitReader.java:161
currentSplitId = null;
emittedFinishedSplitId = null;
}
}
private void checkNeedStopBinlogReader() {
// TODO Currently not supported
}
protected void checkSplitOrStartNext() throws IOException {
// the stream fetcher should keep alive
if (currentFetcher instanceof IncrementalSourceStreamFetcher) {
return;
}
if (canAssignNextSplit()) {
final SourceSplitBase nextSplit = splits.poll();
if (nextSplit == null) {
throw new IOException("Cannot fetch from another split - no split remaining.");
}
currentSplitId = nextSplit.splitId();
emittedFinishedSplitId = null;
if (nextSplit.isSnapshotSplit()) {
if (currentFetcher == null) {
final FetchTask.Context taskContext =
dataSourceDialect.createFetchTaskContext(nextSplit, sourceConfig);
currentFetcher = new IncrementalSourceScanFetcher(taskContext, subtaskId);
}
} else {
// point from snapshot split to incremental split
if (currentFetcher != null) {
log.info(
"It's turn to read incremental split, close current snapshot fetcher.");
currentFetcher.close();
}
final FetchTask.Context taskContext =View on GitHub (pinned to cf67b549a7)
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
Defensive patterns
Strategy: try-catch
Validate before calling
// Before fetch: confirm a split is queued or a split is active
if (canAssignNextSplit() && splits.isEmpty() && currentSplitId == null) {
LOG.warn("No split available; skipping fetch cycle instead of polling null");
return;
} Try / catch
try { checkSplitOrStartNext(); }
catch (IOException e) {
if (e.getMessage().contains("no split remaining")) { restartFromLastCheckpoint(); }
else { throw e; }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Enumerator and reader state divergence after checkpoint restore; splits consumed but reader state (emittedFinishedSplitId/currentSplitId) not updated consistently; engine bug in split delivery order.
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
- Invalid state: currentSplitId is null when emitting records.
- No split assigned
- Could not find existing binlog information while attempting
- Read snapshot for split %s fail
- Reader {} is not registered. Pending splits {} are not assig
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/7c71935926c6e475.
Report an issue: GitHub.