apache/seatunnel · error · IllegalArgumentException

Unsupported pending split value type ${value.getClass().getN

Error message

Unsupported pending split value type ${value.getClass().getName()} for reader ${entry.getKey()}.

What it means

Thrown by TiDBSourceCheckpointState.normalizePendingSplit when a reader's pending-splits entry loaded from checkpoint state is neither a TiDBSourceSplit, a List, nor null. The checkpoint restore path expects a strictly typed structure and rejects any other stored value type.

Source

Thrown at seatunnel-connectors-v2/connector-cdc/connector-cdc-tidb/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/tidb/source/enumerator/TiDBSourceCheckpointState.java:81

    private static Map<Integer, List<TiDBSourceSplit>> normalizePendingSplit(
            Map<Integer, ?> pendingSplit) {
        Map<Integer, List<TiDBSourceSplit>> normalizedPendingSplit = new HashMap<>();
        if (pendingSplit == null) {
            return normalizedPendingSplit;
        }
        for (Map.Entry<Integer, ?> entry : pendingSplit.entrySet()) {
            Object value = entry.getValue();
            if (value instanceof TiDBSourceSplit) {
                normalizedPendingSplit.put(
                        entry.getKey(),
                        new ArrayList<>(Collections.singletonList((TiDBSourceSplit) value)));
            } else if (value instanceof List) {
                normalizedPendingSplit.put(entry.getKey(), copyPendingSplits((List<?>) value));
            } else if (value == null) {
                normalizedPendingSplit.put(entry.getKey(), new ArrayList<>());
            } else {
                throw new IllegalArgumentException(
                        String.format(
                                "Unsupported pending split value type %s for reader %s.",
                                value.getClass().getName(), entry.getKey()));
            }
        }
        return normalizedPendingSplit;
    }

    private static List<TiDBSourceSplit> copyPendingSplits(List<?> pendingSplits) {
        List<TiDBSourceSplit> copiedPendingSplits = new ArrayList<>();
        for (Object pendingSplit : pendingSplits) {
            if (!(pendingSplit instanceof TiDBSourceSplit)) {
                throw new IllegalArgumentException(
                        String.format(
                                "Unsupported pending split list value type %s.",
                                pendingSplit == null ? "null" : pendingSplit.getClass().getName()));
            }
            copiedPendingSplits.add((TiDBSourceSplit) pendingSplit);

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Discard the incompatible checkpoint/savepoint and restart the job from a fresh state
  2. Use a checkpoint produced by the same connector version (match versions between save and restore)
  3. Inspect the state file to find the offending reader key and its stored value type
  4. Migrate the state by converting legacy split entries into TiDBSourceSplit lists before restore

Example fix

// before: checkpoint holds legacy String split descriptors
"pendingSplits": {"reader-0": "split-1,split-2"}
// after: state as list of TiDBSourceSplit objects
"pendingSplits": {"reader-0": [{"splitId": "split-1", ...}, {"splitId": "split-2", ...}]}
Defensive patterns

Strategy: validation

Validate before calling

// Validate pending split state shape before restore
for (Map.Entry<String, Object> e : pendingSplits.entrySet()) {
    Object v = e.getValue();
    if (!(v == null || v instanceof TiDBSourceSplit || v instanceof List)) {
        throw new IllegalStateException("Bad pending split for reader " + e.getKey());
    }
}

Type guard

boolean isRestorablePendingSplit(Object v) {
    return v == null || v instanceof TiDBSourceSplit
        || (v instanceof List<?> l && l.stream().allMatch(s -> s instanceof TiDBSourceSplit));
}

Try / catch

try {
    state = TiDBSourceCheckpointState.fromCheckpoint(rawState);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Unsupported pending split value type")) {
        LOG.error("Checkpoint written by incompatible version; restart without restore");
    }
    throw e;
}

Prevention

When it happens

Trigger: Restoring from a checkpoint/savepoint where the pendingSplits map contains an unexpected value type — e.g. a state format produced by a different connector version, or corrupted/manually edited state where the value is a String or other object.

Common situations: Upgrading or downgrading SeaTunnel between versions that changed the pending-splits state schema; resuming from an incompatible checkpoint file; state mutated by custom code.

Related errors


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