apache/beam · error · NotImplementedError

NotImplementedError

Error message

NotImplementedError

What it means

iobase.RangeTracker's abstract fraction_to_position() has no default implementation; the base class raises NotImplementedError. Concrete RangeTracker implementations must override it to convert a fraction into a position.

Source

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

      if self._last_claim is self.UNSTARTED or self._last_claim < position:
        fraction = self.position_to_fraction(
            position, start=self._start_position, end=self._stop_position)
        self._stop_position = position
        return position, fraction

  def fraction_consumed(self):
    if self._last_claim is self.UNSTARTED:
      return 0
    else:
      return self.position_to_fraction(
          self._last_claim, self._start_position, self._stop_position)

  def fraction_to_position(self, fraction, start, end):
    """
    Converts a fraction between 0 and 1 to a position between start and end.
    """
    raise NotImplementedError

  def position_to_fraction(self, position, start, end):
    """Returns the fraction of keys in the range [start, end) that
    are less than the given key.
    """
    raise NotImplementedError


class UnsplittableRangeTracker(iobase.RangeTracker):
  """A RangeTracker that always ignores split requests.

  This can be used to make a given
  :class:`~apache_beam.io.iobase.RangeTracker` object unsplittable by
  ignoring all calls to :meth:`.try_split()`. All other calls will be delegated
  to the given :class:`~apache_beam.io.iobase.RangeTracker`.
  """
  def __init__(self, range_tracker):
    """Initializes UnsplittableRangeTracker.

View on GitHub (pinned to 12126d8942)

Solutions

  1. Override fraction_to_position(fraction, start, end) in your RangeTracker subclass with a real conversion (e.g. start + fraction*(end-start)).
  2. If the source cannot support fractional splitting, wrap the tracker in UnsplittableRangeTracker so the method is never called.
  3. Prefer implementing a RestrictionTracker for splittable DoFns instead of the legacy RangeTracker API.

Example fix

// before
class MyTracker(iobase.RangeTracker):
  pass  # fraction_to_position not implemented
// after
class MyTracker(iobase.RangeTracker):
  def fraction_to_position(self, fraction, start, end):
    return int(start + fraction * (end - start))
Defensive patterns

Strategy: fallback

Validate before calling

if type(tracker).fraction_to_position is iobase.RangeTracker.fraction_to_position:
  tracker = UnsplittableRangeTracker(tracker)

Type guard

def implements_fraction_to_position(tracker) -> bool:
  return type(tracker).fraction_to_position is not iobase.RangeTracker.fraction_to_position

Try / catch

try:
  pos = tracker.position_at_fraction(f)
except NotImplementedError:
  pos = None  # tracker does not support fractional positioning

Prevention

When it happens

Trigger: Calling position_at_fraction() on a RangeTracker subclass (used by work rebalancing) that inherits from iobase.RangeTracker but does not override fraction_to_position.

Common situations: Implementing a custom RangeTracker for a custom source and forgetting to implement fraction_to_position; enabling dynamic work rebalancing, which then invokes it at runtime.

Understand the failure class

Background: "NotImplementedError: Subclasses should override this method" / "must be implemented" — abstract method errors explained — this error's family across 40 libraries.

Related errors


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