apache/beam · error · ValueError

Position to be claimed cannot be smaller than the start posi

Error message

Position to be claimed cannot be smaller than the start position of the range. Tried to claim position %r for the range [%r, %r)

What it means

OffsetRestrictionTracker.try_claim() rejects positions below the start of the restriction range. Beam raises this ValueError because the tracker can only acknowledge claims inside [start, stop); claiming before start would violate the restriction contract established at construction.

Source

Thrown at sdks/python/apache_beam/io/restriction_trackers.py:127

    return RestrictionProgress(fraction=fraction)

  def start_position(self):
    return self._range.start

  def stop_position(self):
    return self._range.stop

  def try_claim(self, position):
    if (self._last_claim_attempt is not None and
        position <= self._last_claim_attempt):
      raise ValueError(
          'Positions claimed should strictly increase. Trying to claim '
          'position %d while last claim attempt was %d.' %
          (position, self._last_claim_attempt))

    self._last_claim_attempt = position
    if position < self._range.start:
      raise ValueError(
          'Position to be claimed cannot be smaller than the start position '
          'of the range. Tried to claim position %r for the range [%r, %r)' %
          (position, self._range.start, self._range.stop))

    if self._range.start <= position < self._range.stop:
      self._current_position = position
      return True

    return False

  def try_split(self, fraction_of_remainder):
    if not self._checkpointed:
      if self._last_claim_attempt is None:
        cur = self._range.start - 1
      else:
        cur = self._last_claim_attempt
      split_point = (
          cur + int(max(1, (self._range.stop - cur) * fraction_of_remainder)))

View on GitHub (pinned to 12126d8942)

Solutions

  1. Initialize the iteration cursor from restriction.start() (or tracker.try_split results) instead of 0
  2. Clamp or skip positions below range.start before claiming
  3. Check for off-by-one errors where a split boundary was applied twice
  4. If work before start is needed, request a restriction that includes it rather than claiming outside

Example fix

// before
position = 0
while tracker.try_claim(position): ...
// after
position = restriction.start()
while tracker.try_claim(position): ...
Defensive patterns

Strategy: validation

Validate before calling

def safe_claim(tracker, position):
    start = tracker.current_restriction().start
    if position < start:
        position = start
    return tracker.try_claim(position)

Try / catch

try:
    tracker.try_claim(position)
except ValueError as e:
    logger.error('Claim below restriction start: %s', e)

Prevention

When it happens

Trigger: Calling try_claim(position) where position < restriction.start, e.g. iterating a file from byte 0 while the restriction was split to start at byte 1000.

Common situations: Custom splittable DoFns that ignore the restriction's start when iterating (always starting from zero), or reusing a loop variable initialized outside the range after splitting.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/975536938e673d6d. Report an issue: GitHub.