{"record":{"id":"59df8800d73f0f8f","repo":"apache/beam","slug":"get-position-for-fraction-consumed-is-not-applicable-for-an","errorCode":null,"errorMessage":"get_position_for_fraction_consumed is not applicable for an unbounded range","messagePattern":"get_position_for_fraction_consumed is not applicable for an unbounded range","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/io/range_trackers.py","lineNumber":193,"sourceCode":"\n  def fraction_consumed(self):\n    with self._lock:\n      # self.last_record_start may become larger than self.end_offset when\n      # reading the records since any record that starts before the first 'split\n      # point' at or after the defined 'stop offset' is considered to be within\n      # the range of the OffsetRangeTracker. Hence fraction could be > 1.\n      # self.last_record_start is initialized to -1, hence fraction may be < 0.\n      # Bounding the to range [0, 1].\n      return self.position_to_fraction(\n          self._last_record_start, self.start_position(), self.stop_position())\n\n  def position_to_fraction(self, pos, start, stop):\n    fraction = 1.0 * (pos - start) / (stop - start) if start != stop else 0.0\n    return max(0.0, min(1.0, fraction))\n\n  def position_at_fraction(self, fraction):\n    if self.stop_position() == OffsetRangeTracker.OFFSET_INFINITY:\n      raise Exception(\n          'get_position_for_fraction_consumed is not applicable for an '\n          'unbounded range')\n    return int(\n        math.ceil(\n            self.start_position() + fraction *\n            (self.stop_position() - self.start_position())))\n\n  def split_points(self):\n    with self._lock:\n      split_points_consumed = (\n          0 if self._split_points_seen == 0 else self._split_points_seen - 1)\n      split_points_unclaimed = (\n          self._split_points_unclaimed_callback(self.stop_position())\n          if self._split_points_unclaimed_callback else\n          iobase.RangeTracker.SPLIT_POINTS_UNKNOWN)\n      split_points_remaining = (\n          iobase.RangeTracker.SPLIT_POINTS_UNKNOWN if split_points_unclaimed\n          == iobase.RangeTracker.SPLIT_POINTS_UNKNOWN else","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/range_trackers.py#L175-L211","documentation":"OffsetRangeTracker.position_at_fraction() computes the position corresponding to a fraction of the consumed range. It raises a plain Exception when the range is unbounded (stop_position() == OFFSET_INFINITY), because a fraction of infinity is undefined.","triggerScenarios":"Calling position_at_fraction(fraction) (used by dynamic work rebalancing / split_at_fraction) on an OffsetRangeTracker whose stop position is OFFSET_INFINITY, e.g. an unbounded streaming source or a tracker built with stop=None/infinity.","commonSituations":"Running autoscaling/dynamic work rebalancing against a custom unbounded source; converting an infinite OffsetRangeTracker from streaming code into a splittable-DoFn context that requests fractional splits.","solutions":["Only use a bounded range for sources that support fractional splitting: construct OffsetRangeTracker with a finite stop position.","Implement position_at_fraction in your custom RangeTracker subclass to return a sensible position (e.g. last attempted position) for unbounded ranges.","Disable dynamic work rebalancing for this source (or wrap it in UnsplittableRangeTracker) so position_at_fraction is never called."],"exampleFix":"// before\ntracker = beam.io.range_trackers.OffsetRangeTracker(0, OffsetRangeTracker.OFFSET_INFINITY)\npos = tracker.position_at_fraction(0.5)\n// after\ntracker = beam.io.range_trackers.OffsetRangeTracker(0, 1000)  # finite stop\npos = tracker.position_at_fraction(0.5)","handlingStrategy":"validation","validationCode":"if tracker.stop_position() == OffsetRangeTracker.OFFSET_INFINITY:\n  raise ValueError('fractional split not supported for unbounded range')","typeGuard":"def supports_fractional_split(tracker) -> bool:\n  return tracker.stop_position() != OffsetRangeTracker.OFFSET_INFINITY","tryCatchPattern":"try:\n  pos = tracker.position_at_fraction(0.5)\nexcept Exception:\n  pos = tracker.stop_position()  # cannot split unbounded range","preventionTips":["Use finite stop positions for splittable bounded sources","Disable dynamic work rebalancing for unbounded sources","Override position_at_fraction in custom trackers"],"tags":["python","apache-beam","io","unbounded-source"],"backgroundTag":"unsupported-operation","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"}