apache/beam · error · Exception

get_position_for_fraction_consumed is not applicable for an…

Error message

get_position_for_fraction_consumed is not applicable for an unbounded range

What it means

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.

Solutions

  1. Only use a bounded range for sources that support fractional splitting: construct OffsetRangeTracker with a finite stop position.
  2. Implement position_at_fraction in your custom RangeTracker subclass to return a sensible position (e.g. last attempted position) for unbounded ranges.
  3. Disable dynamic work rebalancing for this source (or wrap it in UnsplittableRangeTracker) so position_at_fraction is never called.

Example fix

// before
tracker = beam.io.range_trackers.OffsetRangeTracker(0, OffsetRangeTracker.OFFSET_INFINITY)
pos = tracker.position_at_fraction(0.5)
// after
tracker = beam.io.range_trackers.OffsetRangeTracker(0, 1000)  # finite stop
pos = tracker.position_at_fraction(0.5)
Defensive patterns

Strategy: validation

Validate before calling

if tracker.stop_position() == OffsetRangeTracker.OFFSET_INFINITY:
  raise ValueError('fractional split not supported for unbounded range')

Type guard

def supports_fractional_split(tracker) -> bool:
  return tracker.stop_position() != OffsetRangeTracker.OFFSET_INFINITY

Try / catch

try:
  pos = tracker.position_at_fraction(0.5)
except Exception:
  pos = tracker.stop_position()  # cannot split unbounded range

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at sdks/python/apache_beam/io/range_trackers.py:193

  def fraction_consumed(self):
    with self._lock:
      # self.last_record_start may become larger than self.end_offset when
      # reading the records since any record that starts before the first 'split
      # point' at or after the defined 'stop offset' is considered to be within
      # the range of the OffsetRangeTracker. Hence fraction could be > 1.
      # self.last_record_start is initialized to -1, hence fraction may be < 0.
      # Bounding the to range [0, 1].
      return self.position_to_fraction(
          self._last_record_start, self.start_position(), self.stop_position())

  def position_to_fraction(self, pos, start, stop):
    fraction = 1.0 * (pos - start) / (stop - start) if start != stop else 0.0
    return max(0.0, min(1.0, fraction))

  def position_at_fraction(self, fraction):
    if self.stop_position() == OffsetRangeTracker.OFFSET_INFINITY:
      raise Exception(
          'get_position_for_fraction_consumed is not applicable for an '
          'unbounded range')
    return int(
        math.ceil(
            self.start_position() + fraction *
            (self.stop_position() - self.start_position())))

  def split_points(self):
    with self._lock:
      split_points_consumed = (
          0 if self._split_points_seen == 0 else self._split_points_seen - 1)
      split_points_unclaimed = (
          self._split_points_unclaimed_callback(self.stop_position())
          if self._split_points_unclaimed_callback else
          iobase.RangeTracker.SPLIT_POINTS_UNKNOWN)
      split_points_remaining = (
          iobase.RangeTracker.SPLIT_POINTS_UNKNOWN if split_points_unclaimed
          == iobase.RangeTracker.SPLIT_POINTS_UNKNOWN else

View on GitHub (pinned to 12126d8942)