apache/beam · error · TypeCheckError
Transform '{full_label}' expects a PCollection as input. Got
Error message
Transform '{full_label}' expects a PCollection as input. Got a PBegin/Pipeline instead. What it means
Beam forbids applying a ParDo directly to PBegin (the placeholder input of a Pipeline). A ParDo needs a real PCollection, so _apply_internal raises TypeCheckError with the transform's full label saying a PCollection was expected but a PBegin/Pipeline was given.
Source
Thrown at sdks/python/apache_beam/pipeline.py:806
current = AppliedPTransform(
self._current_transform(),
transform,
full_label,
inputs,
None,
annotations=self._current_annotations())
self._current_transform().add_part(current)
try:
self.transforms_stack.append(current)
type_options = self._options.view_as(TypeOptions)
if type_options.pipeline_type_check:
transform.type_check_inputs(pvalueish)
if isinstance(pvalueish, pvalue.PBegin) and isinstance(transform, ParDo):
full_label = self._current_transform().full_label
raise TypeCheckError(
f"Transform '{full_label}' expects a PCollection as input. "
"Got a PBegin/Pipeline instead.")
self._assert_not_applying_PDone(pvalueish, transform)
pvalueish_result = self.runner.apply(transform, pvalueish, self._options)
if type_options is not None and type_options.pipeline_type_check:
transform.type_check_outputs(pvalueish_result)
for tag, result in ptransform.get_named_nested_pvalues(pvalueish_result):
assert isinstance(result, (pvalue.PValue, pvalue.DoOutputsTuple))
# Make sure we set the producer only for a leaf node in the transform
# DAG. This way we preserve the last transform of a composite transform
# as being the real producer of the result.
if result.producer is None:
result.producer = currentView on GitHub (pinned to 12126d8942)
Solutions
- Start the pipeline with a source: pipeline | beam.Create([...]) or a Read transform, then apply the ParDo.
- Check the `|` chain starts from a PCollection, not the Pipeline.
- If you meant a side effect/impulse, use pipeline | beam.Impulse() (which yields PBegin-compatible flow via a DoFn) carefully — generally use Create/Read.
Example fix
// before result = pipeline | beam.Map(lambda x: x * 2) // after result = pipeline | beam.Create([1, 2, 3]) | beam.Map(lambda x: x * 2)
Defensive patterns
Strategy: type-guard
Validate before calling
from apache_beam.pvalue import PBegin
def ensure_not_pbegin(x):
assert not isinstance(x, PBegin), 'ParDo needs a PCollection, not PBegin/Pipeline' Type guard
from apache_beam.pvalue import PBegin, PCollection
def is_applyable_input(x) -> bool:
return isinstance(x, PCollection) and not isinstance(x, PBegin) Try / catch
try:
out = pcoll_or_pipeline | beam.Map(fn)
except TypeCheckError as e:
if 'PBegin/Pipeline' in str(e):
raise ValueError('chain from a PCollection; add beam.Create/Read first') from e Prevention
- Always start pipelines with a source (Create/Read)
- Chain transforms from PCollections, never from the Pipeline object
- Use pipeline | 'label' >> pattern carefully at the start of graphs
When it happens
Trigger: pipeline | beam.Map(fn) or pipeline | beam.ParDo(...) applied straight to the Pipeline object instead of a PCollection; forgetting an initial Create/Read step.
Common situations: Typos where the first transform chains off `pipeline` instead of `pcoll`; refactoring that removed the source transform; examples that mistakenly start pipelines with a Map.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Transform "{full_label}" was applied to the output of an obj
- Returning a %s from a ParDo or FlatMap is not allowed. Pleas
- Input to _GroupByKeyOnly must be a PCollection of windowed k
- Input to GroupByKey must be a PCollection with elements comp
- ParDo must be called with a DoFn instance.
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/2bafe44992fdf1fe.
Report an issue: GitHub.