{"record":{"id":"17d7650679652072","repo":"apache/beam","slug":"positions-must-be-claimed-in-order-claim-s-attempted-after","errorCode":null,"errorMessage":"Positions must be claimed in order: claim '%s' attempted after claim '%s'","messagePattern":"Positions must be claimed in order: claim '(.+?)' attempted after claim '(.+?)'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/io/range_trackers.py","lineNumber":246,"sourceCode":"  UNSTARTED = object()\n\n  def __init__(self, start_position=None, stop_position=None):\n    self._start_position = start_position\n    self._stop_position = stop_position\n    self._lock = threading.Lock()\n    self._last_claim = self.UNSTARTED\n\n  def start_position(self):\n    return self._start_position\n\n  def stop_position(self):\n    with self._lock:\n      return self._stop_position\n\n  def try_claim(self, position):\n    with self._lock:\n      if self._last_claim is not self.UNSTARTED and position < self._last_claim:\n        raise ValueError(\n            \"Positions must be claimed in order: \"\n            \"claim '%s' attempted after claim '%s'\" %\n            (position, self._last_claim))\n      elif self._start_position is not None and position < self._start_position:\n        raise ValueError(\n            \"Claim '%s' is before start '%s'\" %\n            (position, self._start_position))\n      if self._stop_position is None or position < self._stop_position:\n        self._last_claim = position\n        return True\n      else:\n        return False\n\n  def position_at_fraction(self, fraction):\n    return self.fraction_to_position(\n        fraction, self._start_position, self._stop_position)\n\n  def try_split(self, position):","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/range_trackers.py#L228-L264","documentation":"OffsetRangeTracker (restrictions-based) try_claim() enforces claim ordering. It raises ValueError when a position is claimed that is strictly less than the last claimed position, violating the requirement that positions are claimed in monotonically increasing order.","triggerScenarios":"Calling try_claim(position) with position < self._last_claim after a prior successful claim, e.g. a DoFn process loop that rewinds its cursor, or a split/resume path that restarts from an earlier position on the same tracker instance.","commonSituations":"Custom restriction providers (RestrictionTracker) where the process function re-processes elements after a retriable failure without creating a fresh tracker; incorrectly implemented try_split producing overlapping claims.","solutions":["Ensure the process loop iterates positions in strictly increasing order and never rewinds.","After a retriable failure, restart processing from restriction_tracker.current_restriction().start with a fresh tracker rather than re-claiming older positions on the same tracker.","Review try_split/primary-and-residual logic so the primary restriction (which keeps claiming) starts where the residual begins, never before the last claim."],"exampleFix":"// before\npos = start\nwhile try_claim(pos):\n  process(pos)\n  if error: pos = start  # rewinds\n  pos += 1\n// after\npos = start\nwhile try_claim(pos):\n  try:\n    process(pos)\n  except RetryableError:\n    raise  # let runner restart with fresh restriction\n  pos += 1","handlingStrategy":"validation","validationCode":"if tracker._last_claim is not tracker.UNSTARTED and position < tracker._last_claim:\n  raise ValueError('position must not go backwards')","typeGuard":null,"tryCatchPattern":"try:\n  ok = tracker.try_claim(position)\nexcept ValueError:\n  logging.error('claim order violated; restarting from restriction start')","preventionTips":["Iterate positions strictly in increasing order","Never rewind cursors on retriable errors; restart with a fresh tracker","Test try_split implementations for overlap-free primary/residual ranges"],"tags":["python","apache-beam","restriction-tracker"],"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"}