apache/seatunnel · error · java.lang.IllegalStateException

No split assigned

Error message

No split assigned

What it means

In the split-reader's empty-state inner class, nextRecordFromSplit() unconditionally throws IllegalStateException("No split assigned"). This placeholder implementation exists for the state where the reader holds no split, so any request to emit a record in that state is an internal contract violation: the framework should never poll records without a split first being assigned via nextSplit().

Source

Thrown at seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/base/source/reader/IncrementalSourceSplitReader.java:234

        }
        if (splitId.equals(emittedFinishedSplitId)) {
            return NoSplitRecords.INSTANCE;
        }
        emittedFinishedSplitId = splitId;
        return ChangeEventRecords.forFinishedSplit(splitId);
    }

    private static final class NoSplitRecords implements RecordsWithSplitIds<SourceRecords> {
        private static final NoSplitRecords INSTANCE = new NoSplitRecords();

        @Override
        public String nextSplit() {
            return null;
        }

        @Override
        public SourceRecords nextRecordFromSplit() {
            throw new IllegalStateException("No split assigned");
        }

        @Override
        public Set<String> finishedSplits() {
            return Collections.emptySet();
        }
    }
}

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Ensure hasNext()/nextRecordFromSplit() are only called after a non-null split is assigned; check the split-reader state machine in the connector.
  2. Verify the enumerator actually assigns snapshot/incremental splits before the reader starts polling (check split assignment logs).
  3. Upgrade connector-cdc-base; some versions fixed lifecycle ordering between split assignment and record polling.
  4. If you wrote a custom SourceReader, guard nextRecordFromSplit to return null instead of throwing when no split is assigned.

Example fix

// before
public SourceRecords nextRecordFromSplit() {
    throw new IllegalStateException("No split assigned");
}
// after
public SourceRecords nextRecordFromSplit() {
    if (currentSplitId == null) {
        return null; // signal no more records for now
    }
    return pollCurrentSplit();
}
Defensive patterns

Strategy: type-guard

Validate before calling

// poll only when a split is available
if (reader.nextSplit() == null) { return; }

Type guard

boolean hasAssignedSplit = currentSplitId != null;
if (!hasAssignedSplit) return null;

Try / catch

try {
    record = reader.nextRecordFromSplit();
} catch (IllegalStateException e) {
    if (e.getMessage().equals("No split assigned")) { /* wait for assignment */ }
}

Prevention

When it happens

Trigger: The source reader framework calls nextRecordFromSplit() while the active split-reader state has nextSplit() returning null (no assigned split), e.g. after all splits finished or before assignment.

Common situations: Engine asking for records from a reader that just finished its splits; a state-transition bug where the reader wasn't switched back to a records-holding state; custom CDC source code invoking the reader API out of order.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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