apache/seatunnel · error · IllegalStateException
Vitess CDC reader only supports one active streaming split.
Error message
Vitess CDC reader only supports one active streaming split.
What it means
Thrown by VitessSourceReader.addSplits when splits are added while the reader already holds an active split. Vitess CDC streams exactly one streaming split per reader, so concurrent or duplicate split assignment violates the reader's state invariant.
Solutions
- Ensure the split enumerator assigns at most one streaming split per reader (deregister/invalidate the reader after assignment)
- On restore, clear or replace the existing split instead of appending (guard/replace state under the stateLock)
- Update engine/checkpoint logic so addSplits is idempotent for the same split
Example fix
// before
reader.addSplits(existingSplits); // called again after restore
// after
if (reader currently holds no split) { reader.addSplits(existingSplits); } Defensive patterns
Strategy: try-catch
Validate before calling
// caller-side: only hand each reader a split when it holds none
if (readerState.hasActiveSplit()) {
throw new IllegalStateException("reader already has an active streaming split");
} Type guard
boolean canAcceptSplits(VitessSourceReader r) { return !r.hasActiveSplit(); } Try / catch
try {
reader.addSplits(splits);
} catch (IllegalStateException e) {
// split already active — skip duplicate assignment or replace existing split
} Prevention
- Make split assignment idempotent on checkpoint restore
- Configure enumerator parallelism so each reader receives exactly one split
- Track per-reader split assignment state in custom enumerators
When it happens
Trigger: Calling addSplits with a non-empty list while sourceSplits is non-empty — e.g. a restore path delivering splits twice, or an enumerator assigning a second split to an already-active reader (also observed in tests testCheckpointRestorePreservesOffsetsAndTableIdentity, testSpecificStartupUsesCapturedVgtid exercising restore).
Common situations: Checkpoint/restore delivering the same split again on top of an existing one; misconfigured enumerator parallelism sending more than one split to a reader; replay of addSplits after recovery.
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
- startup.specific-offset.vgtid is required when…
- tables_configs can not be empty.
- Unsupported Vitess catalog SQL type:
- Vitess CDC accepts either table-names or table-pattern, but…
- Vitess CDC bootstrap schema does not support catalog SQL…
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/2e553b0322b868c1.
Report an issue: GitHub.
Appendix: source
Thrown at seatunnel-connectors-v2/connector-cdc/connector-cdc-vitess/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/vitess/source/reader/VitessSourceReader.java:147
@Override
public List<VitessSourceSplit> snapshotState(long checkpointId) {
synchronized (stateLock) {
if (runtime != null && !sourceSplits.isEmpty()) {
Map<String, byte[]> runtimeTableSchemas = runtime.snapshotTableSchemas();
if (runtimeTableSchemas != null && !runtimeTableSchemas.isEmpty()) {
sourceSplits.get(0).setTableSchemas(runtimeTableSchemas);
}
}
return sourceSplits.stream().map(VitessSourceSplit::copy).collect(Collectors.toList());
}
}
@Override
public void addSplits(List<VitessSourceSplit> splits) {
synchronized (stateLock) {
if (!sourceSplits.isEmpty() && splits != null && !splits.isEmpty()) {
throw new IllegalStateException(
"Vitess CDC reader only supports one active streaming split.");
}
if (splits != null) {
for (VitessSourceSplit split : splits) {
sourceSplits.add(split.copy());
}
}
if (runtime == null && !sourceSplits.isEmpty()) {
// Start Debezium as soon as the split arrives so latest startup does not miss
// changes produced before the framework issues the first pollNext call.
runtime = new VitessStreamingRuntime(sourceConfig, sourceSplits.get(0));
}
}
}
@Override
public void handleNoMoreSplits() {}
View on GitHub (pinned to cf67b549a7)