apache/beam · error · IllegalStateException
The first record [starting at %d] must be at a split point
Error message
The first record [starting at %d] must be at a split point
What it means
OffsetRangeTracker.tryReturnRecordAt enforces that the very first record claimed by a reader starts exactly at a split point (i.e. the reader was positioned at the beginning of its assigned range). If the tracker has not started and the record is claimed as not being at a split point, the range model is broken — the runner could not tell whether the record was already processed — so it fails fast with IllegalStateException.
Source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/io/range/OffsetRangeTracker.java:88
@Override
public synchronized Long getStartPosition() {
return startOffset;
}
@Override
public synchronized Long getStopPosition() {
return stopOffset;
}
@Override
public boolean tryReturnRecordAt(boolean isAtSplitPoint, Long recordStart) {
return tryReturnRecordAt(isAtSplitPoint, recordStart.longValue());
}
public synchronized boolean tryReturnRecordAt(boolean isAtSplitPoint, long recordStart) {
if (!isStarted() && !isAtSplitPoint) {
throw new IllegalStateException(
String.format("The first record [starting at %d] must be at a split point", recordStart));
}
if (recordStart < startOffset) {
throw new IllegalStateException(
String.format(
"Trying to return record [starting at %d] which is before the start offset [%d]",
recordStart, startOffset));
}
if (recordStart < lastRecordStart) {
throw new IllegalStateException(
String.format(
"Trying to return record [starting at %d] "
+ "which is before the last-returned record [starting at %d]",
recordStart, lastRecordStart));
}
if (lastRecordStart == -1) {
startOffset = recordStart;View on GitHub (pinned to 12126d8942)
Solutions
- Ensure the reader positions itself at a record/split boundary before claiming the first record (seek to the next delimiter after startOffset).
- Report isAtSplitPoint=true for the first record if the reader genuinely begins at a record boundary (the common case at startOffset).
- Fix the split logic so split positions always fall on record boundaries (e.g. split only at newline positions).
Example fix
// before tracker.tryReturnRecordAt(false, firstRecordStart); // first claim mid-record // after long boundary = findNextRecordStart(startOffset); // seek to split point tracker.tryReturnRecordAt(true, boundary);
Defensive patterns
Strategy: validation
Validate before calling
checkState(tracker.isStarted() || isAtSplitPoint, "first claimed record must be at a split point");
Try / catch
try {
tracker.tryReturnRecordAt(isAtSplitPoint, recordStart);
} catch (IllegalStateException e) {
// reposition reader to the next record boundary and retry
} Prevention
- Position readers at record boundaries (split points) before the first claim.
- Report the first claimed record with isAtSplitPoint=true when starting at startOffset.
- Design split logic so offsets always fall on record delimiters.
When it happens
Trigger: A source reader calls tryReturnRecordAt(false, recordStart) for the first record after the tracker was created (start() path before any record was returned), i.e. claiming an initial record that is not at position startOffset / not at a split boundary.
Common situations: Custom offset-based sources whose reader begins mid-record after a split/resume (e.g. a file source that splits at byte offsets without splitting at newline boundaries); restoring from a checkpoint at an offset that lands inside a record; tests constructing trackers and immediately claiming non-split-point records.
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
- Trying to return record [starting at %d] which is before the
- Failed closing channel to %s
- Error determining if %s allows dynamic splitting
- File spec %s not found
- Error matching file spec %s: status %s
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/82dc9286b09af10c.
Report an issue: GitHub.