apache/beam · error · RuntimeError

Start Bundle should not output any elements but got %s

Error message

Start Bundle should not output any elements but got %s

What it means

Beam DoFn lifecycle requires that start_bundle produces no output; only process() and finish_bundle() may emit elements. start_bundle_outputs raises RuntimeError if the start_bundle method returned anything other than None.

Source

Thrown at sdks/python/apache_beam/runners/common.py:1856

      for timestamp in windowed_batch.timestamps:
        watermark_estimator.observe_timestamp(timestamp)

    if tag is None:
      self.main_receivers.receive_batch(windowed_batch)
    else:
      self.tagged_receivers[tag].receive_batch(windowed_batch)

  def _verify_batch_output(self, result):
    if isinstance(result, (WindowedValue, TimestampedValue)):
      raise TypeError(
          f"Received {type(result).__name__} from DoFn that was "
          "expected to produce a batch.")

  def start_bundle_outputs(self, results):
    """Validate that start_bundle does not output any elements"""
    if results is None:
      return
    raise RuntimeError(
        'Start Bundle should not output any elements but got %s' % results)

  def finish_bundle_outputs(self, results):
    """Dispatch the result of finish_bundle to the appropriate receivers.

    A value wrapped in a TaggedOutput object will be unwrapped and
    then dispatched to the appropriate indexed output.
    """
    if results is None:
      return

    for result in results:
      tag = None
      if isinstance(result, TaggedOutput):
        tag = result.tag
        if not isinstance(tag, str):
          raise TypeError('In %s, tag %s is not a string' % (self, tag))
        result = result.value

View on GitHub (pinned to 12126d8942)

Solutions

  1. Remove the return/yield statements from start_bundle; perform only per-bundle setup (e.g. initializing clients).
  2. Move element emission to process() (per element) or finish_bundle() (per bundle, must yield WindowedValue).
  3. If side-effect setup is needed per window instead, restructure the pipeline with windowing-aware transforms.

Example fix

// before
def start_bundle(self):
    yield 'warmup'  # RuntimeError
// after
def start_bundle(self):
    self.client = create_client()  # setup only, no output
Defensive patterns

Strategy: validation

Validate before calling

assert start_bundle() is None, 'start_bundle must not produce output'

Type guard

def is_valid_start_bundle_result(r):
    return r is None

Try / catch

try:
    invoker.invoke_start_bundle()
except RuntimeError as e:
    if 'Start Bundle should not output' in str(e):
        raise ValueError('DoFn.start_bundle must not yield/return elements') from e
    raise

Prevention

When it happens

Trigger: Implementing `def start_bundle(self)` in a DoFn with a `return some_value` (yield also counts, since a generator result is passed in) instead of returning None or having no return statement.

Common situations: Misunderstanding the lifecycle API and trying to emit warm-up/initializer elements in start_bundle; copying a finish_bundle pattern into start_bundle.

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