{"record":{"id":"c1ddb2ed42833772","repo":"apache/beam","slug":"unable-to-claim-position-s","errorCode":null,"errorMessage":"Unable to claim position: %s","messagePattern":"Unable to claim position: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/io/tfrecordio.py","lineNumber":206,"sourceCode":"  def __init__(self, file_pattern, coder, compression_type, validate):\n    \"\"\"Initialize a TFRecordSource.  See ReadFromTFRecord for details.\"\"\"\n    super().__init__(\n        file_pattern=file_pattern,\n        compression_type=compression_type,\n        splittable=False,\n        validate=validate)\n    self._coder = coder\n\n  def read_records(self, file_name, offset_range_tracker):\n    if offset_range_tracker.start_position():\n      raise ValueError(\n          'Start position not 0:%s' % offset_range_tracker.start_position())\n\n    current_offset = offset_range_tracker.start_position()\n    with self.open_file(file_name) as file_handle:\n      while True:\n        if not offset_range_tracker.try_claim(current_offset):\n          raise RuntimeError('Unable to claim position: %s' % current_offset)\n        record = _TFRecordUtil.read_record(file_handle)\n        if record is None:\n          return  # Reached EOF\n        else:\n          current_offset += _TFRecordUtil.encoded_num_bytes(record)\n          yield self._coder.decode(record)\n\n\ndef _create_tfrecordio_source(\n    file_pattern=None, coder=None, compression_type=None):\n  # We intentionally disable validation for ReadAll pattern so that reading does\n  # not fail for globs (elements) that are empty.\n  return _TFRecordSource(file_pattern, coder, compression_type, validate=False)\n\n\nclass ReadAllFromTFRecord(PTransform):\n  \"\"\"A ``PTransform`` for reading a ``PCollection`` of TFRecord files.\"\"\"\n  def __init__(","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/tfrecordio.py#L188-L224","documentation":"Raised by _TextSource-like TFRecord reading in apache_beam/io/tfrecordio.py when the OffsetRangeTracker refuses to claim the current offset during sequential record iteration. RangeTracker.try_claim returns False when the offset falls outside the restriction assigned to this bundle (e.g. the offset is below start or at/past stop), so the reader cannot proceed. Beam throws RuntimeError to abort the bundle rather than silently reading data owned by another bundle.","triggerScenarios":"Calling read_records on a TFRecord file with an OffsetRangeTracker whose start_position is nonzero while the reader's internal invariant check ('Start position not 0') has passed but a subsequent try_claim(current_offset) fails — i.e. current_offset >= stop_position or < start_position of the tracker, typically from a corrupted or stale offset after resume, or a custom RangeTracker implementation with buggy claim semantics.","commonSituations":"Custom runners or resharding logic computing wrong split offsets for TFRecord sources; restoring from a checkpoint whose recorded offset exceeds the restriction stop; users implementing their own OffsetRangeTracker that returns False from try_claim for positions it already holds; file mutated/truncated between split and read so encoded record sizes shift offsets.","solutions":["Verify the restriction passed to the OffsetRangeTracker matches the actual file offsets (no truncation/appending of the file between split and read).","If you supplied a custom RangeTracker, ensure try_claim(claim) returns True for the current start position and any offset within [start, stop).","Re-split or re-read the file with a full-range restriction (start=0, stop=OFFSET_INFINITY) to confirm the file itself reads cleanly.","Check that checkpoint/resume offsets are taken from the same file generation (compare file size/mtime/ETag)."],"exampleFix":"// before\ncurrent_offset = offset_range_tracker.start_position()\nwhile True:\n  if not offset_range_tracker.try_claim(current_offset):\n    raise RuntimeError('Unable to claim position: %s' % current_offset)\n\n// after\n# use a tracker whose restriction actually covers the offsets you will read\ntracker = OffsetRangeTracker(0, file_size)  # not (resume_offset, resume_offset)\ncurrent_offset = tracker.start_position()\nwhile True:\n  if not tracker.try_claim(current_offset):\n    break  # stop cleanly instead of raising when leaving the restriction\n","handlingStrategy":"try-catch","validationCode":"start = offset_range_tracker.start_position()\nstop = offset_range_tracker.stop_position()\nassert start <= stop, 'invalid restriction: start %s > stop %s' % (start, stop)\n# confirm the file size covers the restriction offsets\nimport os\nassert offset_range_tracker.stop_position() == OFFSET_INFINITY or \\\n    offset_range_tracker.stop_position() <= os.path.getsize(file_name)","typeGuard":"def has_valid_restriction(tracker) -> bool:\n    start = tracker.start_position()\n    stop = getattr(tracker, 'stop_position', lambda: None)()\n    return start is not None and (stop is None or start <= stop)","tryCatchPattern":"try:\n  for record in source.read_records(file_name, tracker):\n    process(record)\nexcept RuntimeError as e:\n  if 'Unable to claim position' in str(e):\n    logger.error('range restriction mismatch for %s: %s', file_name, e)\n    raise BeamIOError from e\n  raise","preventionTips":["Always construct the OffsetRangeTracker from the same file snapshot used for splitting (compare size/ETag).","Never mutate a file between split and read; copy to immutable storage for resharded reads.","If implementing a custom RangeTracker, unit-test try_claim across the full [start, stop) range.","On resume, derive offsets only from the tracker's own start_position, not cached values."],"tags":["apache-beam","python","io","range-tracker","tfrecord"],"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-14T11:17:12.474Z"}