apache/seatunnel · error · java.lang.IllegalArgumentException

splitId must not be null

Error message

splitId must not be null

What it means

ChangeEventRecords.forFinishedSplit is a factory that records a snapshot split as finished; its javadoc and @throws require a non-null splitId. Passing null is rejected immediately with IllegalArgumentException("splitId must not be null"), since a finished split without an id cannot be tracked or acked to the split enumerator.

Source

Thrown at seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/base/source/split/ChangeEventRecords.java:86

    public Set<String> finishedSplits() {
        return finishedSnapshotSplits;
    }

    public static ChangeEventRecords forRecords(
            final String splitId, final Iterator<SourceRecords> recordsForSplit) {
        return new ChangeEventRecords(splitId, recordsForSplit, Collections.emptySet());
    }

    /**
     * Creates a {@link ChangeEventRecords} that only indicates a split is finished.
     *
     * @param splitId the ID of the finished split, must not be null
     * @return a new {@link ChangeEventRecords} instance
     * @throws IllegalArgumentException if splitId is null
     */
    public static ChangeEventRecords forFinishedSplit(final String splitId) {
        if (splitId == null) {
            throw new IllegalArgumentException("splitId must not be null");
        }
        return new ChangeEventRecords(null, null, Collections.singleton(splitId));
    }
}

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Validate the split id before calling forFinishedSplit; throw early at the source of the null.
  2. Trace where the id comes from (usually the assigned SourceSplit's id()) and fix the null propagation.
  3. Check checkpoint state serialization if the null appears only after job restore.
  4. Use the non-null split id from the currently assigned split object instead of a cached variable.

Example fix

// before
String splitId = currentSplit == null ? null : currentSplit.splitId();
ChangeEventRecords.forFinishedSplit(splitId); // throws if null
// after
if (currentSplit != null && currentSplit.splitId() != null) {
    ChangeEventRecords.forFinishedSplit(currentSplit.splitId());
}
Defensive patterns

Strategy: validation

Validate before calling

if (splitId == null) {
    throw new IllegalStateException("Cannot mark finished: split id is null");
}
ChangeEventRecords.forFinishedSplit(splitId);

Try / catch

try {
    ChangeEventRecords.forFinishedSplit(splitId);
} catch (IllegalArgumentException e) {
    log.error("Null split id; check state restore path");
}

Prevention

When it happens

Trigger: Calling ChangeEventRecords.forFinishedSplit(null), typically when the caller derived the split id from a variable that was never assigned, or from a state object where the split id was lost during serialization/restore.

Common situations: Custom CDC source reader code passing an uninitialized split id; deserialization of split state after checkpoint restore producing a null id; copying example code where the id variable is filled later.

Related errors


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