apache/beam · error · ValueError
Start offset must not be 'None'
Error message
Start offset must not be 'None'
What it means
OffsetRangeTracker tracks progress over an integer offset range and cannot represent a None start. Its constructor validates immediately that start is an int (not None), raising ValueError otherwise. A None start would break position comparison and resume logic.
Source
Thrown at sdks/python/apache_beam/io/range_trackers.py:54
_LOGGER = logging.getLogger(__name__)
class OffsetRangeTracker(iobase.RangeTracker):
"""A 'RangeTracker' for non-negative positions of type 'long'."""
# Offset corresponding to infinity. This can only be used as the upper-bound
# of a range, and indicates reading all of the records until the end without
# specifying exactly what the end is.
# Infinite ranges cannot be split because it is impossible to estimate
# progress within them.
OFFSET_INFINITY = float('inf')
def __init__(self, start, end):
super().__init__()
if start is None:
raise ValueError('Start offset must not be \'None\'')
if end is None:
raise ValueError('End offset must not be \'None\'')
assert isinstance(start, int)
if end != self.OFFSET_INFINITY:
assert isinstance(end, int)
assert start <= end
self._start_offset = start
self._stop_offset = end
self._last_record_start = -1
self._last_attempted_record_start = -1
self._offset_of_last_split_point = -1
self._lock = threading.Lock()
self._split_points_seen = 0
self._split_points_unclaimed_callback = NoneView on GitHub (pinned to 12126d8942)
Solutions
- Pass an explicit integer start, e.g. OffsetRangeTracker(0, end).
- Fix the upstream code that computes the start offset so it never yields None.
- Validate/guard inputs before constructing the tracker: assert start_offset is not None.
Example fix
// before OffsetRangeTracker(start_offset, end_offset) # start_offset is None // after OffsetRangeTracker(start_offset if start_offset is not None else 0, end_offset)
Defensive patterns
Strategy: type-guard
Validate before calling
assert start_offset is not None, "start offset required" assert isinstance(start_offset, int)
Type guard
def is_valid_offset(x) -> bool:
return isinstance(x, int) and not isinstance(x, bool) Try / catch
try:
tracker = OffsetRangeTracker(start, end)
except ValueError as e:
logger.error("Bad offset range: %s", e)
tracker = OffsetRangeTracker(0, end) Prevention
- Use OffsetRangeTracker.OFFSET_INFINITY semantics only for the end, never None for start.
- Validate source-computed offsets before constructing trackers.
- Default missing starts to 0 where semantics allow.
When it happens
Trigger: OffsetRangeTracker(None, end) — constructing the tracker with a None start offset, typically because a source read produced no valid range.
Common situations: Custom BatchedSource/RestrictionSource implementations computing offsets from parsed input where the start came back None (missing file header, failed int conversion swallowed upstream).
Related errors
- End offset must not be 'None'
- File object must not be None
- Unable to claim position: %s
- Encountered an Atomic type that is not currently supported b
- The first record [starting at %d] must be at a split point
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/2d064046416eb379.
Report an issue: GitHub.