{"record":{"id":"11646e792e7d7690","repo":"apache/beam","slug":"trying-to-return-record-starting-at-d-which-is-before-the-11646e","errorCode":null,"errorMessage":"Trying to return record [starting at %d] which is before the last-returned record [starting at %d]","messagePattern":"Trying to return record \\[starting at (.+?)\\] which is before the last-returned record \\[starting at (.+?)\\]","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/io/range/OffsetRangeTracker.java","lineNumber":98,"sourceCode":"\n  @Override\n  public boolean tryReturnRecordAt(boolean isAtSplitPoint, Long recordStart) {\n    return tryReturnRecordAt(isAtSplitPoint, recordStart.longValue());\n  }\n\n  public synchronized boolean tryReturnRecordAt(boolean isAtSplitPoint, long recordStart) {\n    if (!isStarted() && !isAtSplitPoint) {\n      throw new IllegalStateException(\n          String.format(\"The first record [starting at %d] must be at a split point\", recordStart));\n    }\n    if (recordStart < startOffset) {\n      throw new IllegalStateException(\n          String.format(\n              \"Trying to return record [starting at %d] which is before the start offset [%d]\",\n              recordStart, startOffset));\n    }\n    if (recordStart < lastRecordStart) {\n      throw new IllegalStateException(\n          String.format(\n              \"Trying to return record [starting at %d] \"\n                  + \"which is before the last-returned record [starting at %d]\",\n              recordStart, lastRecordStart));\n    }\n\n    if (lastRecordStart == -1) {\n      startOffset = recordStart;\n    }\n    lastRecordStart = recordStart;\n\n    if (isAtSplitPoint) {\n      if (recordStart == offsetOfLastSplitPoint) {\n        throw new IllegalStateException(\n            String.format(\n                \"Record at a split point has same offset as the previous split point: \"\n                    + \"previous split point at %d, current record starts at %d\",\n                offsetOfLastSplitPoint, recordStart));","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/io/range/OffsetRangeTracker.java#L80-L116","documentation":"OffsetRangeTracker tracks progress through an offset range for an IO source. tryReturnRecordAt enforces monotonic progress: a record's start offset must never go backwards. The library throws IllegalStateException when a record is returned at an offset earlier than the previously returned record, because this would indicate a broken source producing out-of-order records.","triggerScenarios":"Calling tryReturnRecordAt(recordStart, isAtSplitPoint) with a recordStart value strictly less than the lastRecordStart recorded by the previous call; typically caused by a custom Source/reader restarting from a wrong offset or yielding records out of order.","commonSituations":"Custom Beam IO implementations that restore readers from a stale checkpoint, offset math bugs after range splitting, or readers that yield the same record twice during resumption after a worker failure.","solutions":["Verify the source reader restores its offset correctly in start() after splitAt/resume (lastRecordStart, not startOffset, must be respected).","Ensure records are yielded in strictly increasing start-offset order; drop or skip duplicates before calling tryReturnRecordAt.","If the reader was re-created, recompute the correct resume offset instead of re-reading already-returned records.","Check for split logic that assigns overlapping ranges, causing re-emission of earlier records."],"exampleFix":"// before\ntracker.tryReturnRecordAt(record.getStartOffset(), record.isAtSplitPoint());\n// after\nif (record.getStartOffset() >= lastReturnedStart) {\n  tracker.tryReturnRecordAt(record.getStartOffset(), record.isAtSplitPoint());\n}","handlingStrategy":"validation","validationCode":"if (recordStart < tracker.lastRecordStart) { skipOrLog(recordStart); return; }","typeGuard":null,"tryCatchPattern":"try { tracker.tryReturnRecordAt(offset, atSplit); } catch (IllegalStateException e) { LOG.warn(\"out-of-order record at offset \" + offset, e); }","preventionTips":["Restore reader offsets from lastRecordStart on resume, not a stale value","Unit-test splitAt/resume behavior of custom readers","Assert strictly increasing offsets in reader loops during development"],"tags":["apache-beam","state-violation","offset-tracking"],"backgroundTag":"invalid-state-transition","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}