apache/beam · error · ValueError

max_records_per_bundle must be >= 1, got %r

Error message

max_records_per_bundle must be >= 1, got %r

What it means

max_records_per_bundle bounds how many records are emitted per bundle; it must be at least 1. The constructor raises ValueError for values below 1 (zero or negative), which would make per-bundle limiting meaningless or cause non-termination.

Source

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

    max_records_per_bundle: a busy reader self-checkpoints after emitting this
      many records in one bundle. Must be >= 1. Defaults to 10000.
    max_read_time_seconds: a busy reader self-checkpoints after this many
      seconds in one bundle. Must be > 0. Defaults to 10.0. The deadline is
      checked between records, so a reader that blocks inside ``advance()`` may
      overrun it; ``max_records_per_bundle`` is the hard backstop.

  The bundle self-checkpoints as soon as either cap is reached.
  """
  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()

View on GitHub (pinned to 12126d8942)

Solutions

  1. Pass an integer >= 1 (e.g. max_records_per_bundle=1000)
  2. Clamp or validate the value at the config layer: max(1, configured_value)
  3. If unlimited reads are desired, set a very large value rather than 0

Example fix

# before
reader = Reader(source, max_records_per_bundle=0)
# after
reader = Reader(source, max_records_per_bundle=max(1, configured_batch_size))
Defensive patterns

Strategy: validation

Validate before calling

if int(max_records_per_bundle) < 1:
    raise ValueError('max_records_per_bundle must be >= 1')

Try / catch

try:
    reader = Reader(source, max_records_per_bundle=n)
except ValueError:
    reader = Reader(source, max_records_per_bundle=1000)  # safe default

Prevention

When it happens

Trigger: Initializing the reader with max_records_per_bundle=0 or a negative int, often passed through from config or a CLI flag.

Common situations: Using 0 as a sentinel for 'unlimited' (incorrect here); a config default of 0 leaking into the constructor; arithmetic on a batch-size setting yielding 0.

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/c1ddb75ed5b5ed2c. Report an issue: GitHub.