apache/beam · error · ValueError
OffsetRestrictionTracker is not done since work in range [%s
Error message
OffsetRestrictionTracker is not done since work in range [%s, %s) has not been claimed.
What it means
OffsetRestrictionTracker.check_done() verifies that a splittable-DoFn restriction has been fully claimed before the element can be considered processed. Beam throws this ValueError when the range is non-empty but the last claim attempt never reached stop-1, meaning unclaimed work remains in [start, stop).
Source
Thrown at sdks/python/apache_beam/io/restriction_trackers.py:89
class OffsetRestrictionTracker(RestrictionTracker):
"""An `iobase.RestrictionTracker` implementations for an offset range.
Offset range is represented as OffsetRange.
"""
def __init__(self, offset_range: OffsetRange) -> None:
assert isinstance(offset_range, OffsetRange), offset_range
self._range = offset_range
self._current_position = None
self._last_claim_attempt = None
self._checkpointed = False
def check_done(self):
if (self._range.start != self._range.stop and
(self._last_claim_attempt is None or
self._last_claim_attempt < self._range.stop - 1)):
raise ValueError(
'OffsetRestrictionTracker is not done since work in range [%s, %s) '
'has not been claimed.' % (
self._last_claim_attempt
if self._last_claim_attempt is not None else self._range.start,
self._range.stop))
def current_restriction(self):
return self._range
def current_progress(self) -> RestrictionProgress:
if self._current_position is None:
fraction = 0.0
elif self._range.stop == self._range.start:
# If self._current_position is not None, we must be done.
fraction = 1.0
else:
fraction = (
float(self._current_position - self._range.start) /View on GitHub (pinned to 12126d8942)
Solutions
- Ensure the processing loop claims every position up to stop-1, e.g. while tracker.try_claim(position)
- Remove early breaks/exits that skip claims, or checkpoint instead of exiting
- If the range is genuinely unprocessed, return a deferred residual rather than declaring done
- Verify the restriction passed to the tracker matches the offsets actually iterated
Example fix
// before
while position < restriction.stop:
if not tracker.try_claim(position):
break
if some_condition:
break # leaves offsets unclaimed
position += 1
// after
while tracker.try_claim(position):
process(position)
if some_condition:
return a_deferred_residual(position) # let Beam resume later
position += 1 Defensive patterns
Strategy: validation
Validate before calling
def restriction_is_done(tracker):
rng = tracker.current_restriction()
return rng.start == rng.stop or tracker.last_claim_reached_stop() Try / catch
try:
tracker.check_done()
except ValueError as e:
raise RuntimeError('SDF left unclaimed work; check process loop') from e Prevention
- Drive iteration with while tracker.try_claim(pos) instead of manual bounds
- Never break out of a claim loop without returning a residual deferral
- Test custom SDFs with small ranges to catch off-by-one claims
When it happens
Trigger: Finishing a DoFn process_element without claiming every position in the range — e.g. claiming only positions 0..4 for OffsetRange(0, 10), or never calling try_claim at all before check_done.
Common situations: Custom splittable DoFns with early loop exits (break on a condition), skipped offsets inside a while loop, or forgetting to claim the final offset.
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
- Initializing SDFBoundedSourceRestrictionTracker requires a _
- SDFBoundedSourceRestrictionProvider can only utilize Bounded
- Positions claimed should strictly increase. Trying to claim
- Position to be claimed cannot be smaller than the start posi
- UnboundedSource restriction was neither finished nor checkpo
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/9b8049735d0d5e5b.
Report an issue: GitHub.