apache/beam · error · NotImplementedError

Root provider for [ ] not implemented in runner

Error message

Root provider for [%s] not implemented in runner %s

What it means

Root transforms (no input PCollection) need a RootBundleProvider that seeds initial bundles. get_root_bundle_provider searches the transform's MRO in _root_bundle_providers and raises NotImplementedError when no provider class exists for the transform type.

Solutions

  1. Use a supported root transform (beam.Create, supported file/connector readers).
  2. Register a root bundle provider class for the transform in _root_bundle_providers.
  3. Upgrade apache-beam to a version with support for this root transform.
  4. Switch to a runner that implements the root transform.

Example fix

# before
coll = pipeline | MyCustomRootSource()
# after
coll = pipeline | beam.Create(my_input_iterable)
Defensive patterns

Strategy: validation

Validate before calling

from apache_beam.runners.direct import transform_evaluator as te
if not any(cls in te._TransformEvaluatorRegistry._root_bundle_providers for cls in type(root_transform).__mro__):
    raise ValueError('root transform unsupported by DirectRunner')

Type guard

def has_root_provider(t) -> bool:
    from apache_beam.runners.direct import transform_evaluator as te
    return any(cls in te._TransformEvaluatorRegistry._root_bundle_providers for cls in type(t).__mro__)

Try / catch

try:
    pipeline.run()
except NotImplementedError as e:
    if 'Root provider' in str(e):
        replace_root_with_supported_source()

Prevention

When it happens

Trigger: Executing a pipeline whose root (source) PTransform has no registered root bundle provider in DirectRunner — e.g. an unknown or custom source transform, or a root primitive only implemented for other runners.

Common situations: Using a custom source/root transform locally; a root-level transform added in a newer Beam release than the runner code; misconfigured pipeline where an unsupported connector is the entry point.

Related errors


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

Appendix: source

Thrown at sdks/python/apache_beam/runners/direct/transform_evaluator.py:145

    if not evaluator:
      raise NotImplementedError(
          'Execution of [%s] not implemented in runner %s.' %
          (type(applied_ptransform.transform), self))
    return evaluator(
        self._evaluation_context,
        applied_ptransform,
        input_committed_bundle,
        side_inputs)

  def get_root_bundle_provider(self, applied_ptransform):
    provider_cls = None
    for cls in applied_ptransform.transform.__class__.mro():
      provider_cls = self._root_bundle_providers.get(cls)
      if provider_cls:
        break
    if not provider_cls:
      raise NotImplementedError(
          'Root provider for [%s] not implemented in runner %s' %
          (type(applied_ptransform.transform), self))
    return provider_cls(self._evaluation_context, applied_ptransform)

  def should_execute_serially(self, applied_ptransform):
    """Returns True if this applied_ptransform should run one bundle at a time.

    Some TransformEvaluators use a global state object to keep track of their
    global execution state. For example evaluator for _GroupByKeyOnly uses this
    state as an in memory dictionary to buffer keys.

    Serially executed evaluators will act as syncing point in the graph and
    execution will not move forward until they receive all of their inputs. Once
    they receive all of their input, they will release the combined output.
    Their output may consist of multiple bundles as they may divide their output
    into pieces before releasing.

    Args:

View on GitHub (pinned to 12126d8942)