apache/beam · error · ValueError

poll_interval must be >= 0, got %r

Error message

poll_interval must be >= 0, got %r

What it means

poll_interval controls how long the reader sleeps between polls of the unbounded source; it must be non-negative. The constructor raises ValueError for negative values, since a negative sleep interval is meaningless and would break the polling loop.

Source

Thrown at sdks/python/apache_beam/io/unbounded_source.py:955

  """
  def __init__(
      self,
      source: UnboundedSource,
      poll_interval: float = _DEFAULT_POLL_INTERVAL_SECONDS,
      max_records_per_bundle: int = _DEFAULT_MAX_RECORDS_PER_BUNDLE,
      max_read_time_seconds: float = _DEFAULT_MAX_READ_TIME_SECONDS):
    if not isinstance(source, UnboundedSource):
      raise TypeError('source must be an UnboundedSource, got %r' % (source, ))
    if max_records_per_bundle < 1:
      raise ValueError(
          'max_records_per_bundle must be >= 1, got %r' %
          (max_records_per_bundle, ))
    if max_read_time_seconds <= 0:
      raise ValueError(
          'max_read_time_seconds must be > 0, got %r' %
          (max_read_time_seconds, ))
    if poll_interval < 0:
      raise ValueError(
          'poll_interval must be >= 0, got %r' % (poll_interval, ))
    super().__init__()
    self._source = source
    self._poll_interval = poll_interval
    self._max_records_per_bundle = max_records_per_bundle
    self._max_read_time_seconds = max_read_time_seconds

  def expand(self, pbegin):
    source = self._source
    output_coder = source.default_output_coder()
    # The source is the SDF element used to derive the initial restriction.
    # process() reads from the restriction, so it does not use the element
    # directly.
    output = (
        pbegin
        | 'Create' >> core.Create([source])
        | 'ReadUnbounded' >> core.ParDo(
            _ReadFromUnboundedSourceDoFn(

View on GitHub (pinned to 12126d8942)

Solutions

  1. Pass poll_interval >= 0 (0 means poll continuously without sleeping)
  2. Clamp the value: poll_interval=max(0.0, configured_value)
  3. Fix the config parsing or computation that produced the negative number

Example fix

# before
reader = Reader(source, poll_interval=-1)
# after
reader = Reader(source, poll_interval=max(0.0, configured_interval))
Defensive patterns

Strategy: validation

Validate before calling

if float(poll_interval) < 0:
    raise ValueError('poll_interval must be >= 0')

Try / catch

try:
    reader = Reader(source, poll_interval=p)
except ValueError:
    reader = Reader(source, poll_interval=0.0)  # poll without sleeping

Prevention

When it happens

Trigger: Initializing the reader with poll_interval < 0, e.g. from a misparsed config ('-1'), or a computed interval that went negative.

Common situations: Using -1 as a 'default/disable' sentinel (use 0 instead); parsing a duration with a sign error; subtracting timestamps to derive the interval and getting a negative value.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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