apache/beam · error · ValueError

Positions claimed should strictly increase. Trying to claim

Error message

Positions claimed should strictly increase. Trying to claim position %d while last claim attempt was %d.

What it means

OffsetRestrictionTracker.try_claim() requires claimed positions to strictly increase so Beam can track deterministic progress through a restriction. Beam raises this ValueError when a position is claimed that is less than or equal to the previous claim attempt, since it would loop forever or double-claim work.

Source

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

    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) /
          (self._range.stop - self._range.start))
    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):

View on GitHub (pinned to 12126d8942)

Solutions

  1. Advance the position monotonically before each try_claim call
  2. Never reuse a position value across try_claim calls; keep a separate cursor
  3. If resuming after checkpoint, resume from stop_position()/current_position rather than the original start
  4. Restructure loops that decrement or reset the index

Example fix

// before
for attempt in range(3):
  tracker.try_claim(position)  # same position retried
// after
tracker.try_claim(position)
position += 1  # always move forward before the next claim
Defensive patterns

Strategy: validation

Validate before calling

def safe_claim(tracker, position, last):
    if last is not None and position <= last:
        raise ValueError('positions must strictly increase')
    return tracker.try_claim(position)

Try / catch

try:
    tracker.try_claim(position)
except ValueError as e:
    logger.error('Non-monotonic claim: %s', e)
    position = tracker.current_position() + 1

Prevention

When it happens

Trigger: Calling try_claim with the same position twice (position == last claim) or going backwards (position < last claim), e.g. re-claiming after a failed claim attempt or a loop that decrements the cursor.

Common situations: Buggy custom SDF loops that retry an offset, iterators that restart from the beginning, or checkpoint/resume logic that resets the position variable but not the tracker.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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