apache/beam · error · TypeCheckError

Transform "{full_label}" was applied to the output of "{prod

Error message

Transform "{full_label}" was applied to the output of "{producer_label}" but "{producer_label.split("/")[-1]}" produces no PCollections.

What it means

This TypeCheckError is raised when a PTransform is applied to the output of a transform that produces no PCollections — i.e. the producer's output is a PDone (a placeholder meaning 'nothing left to do'). Apache Beam throws it because applying a downstream transform to a PDone result is meaningless; PDone cannot be consumed by another transform.

Source

Thrown at sdks/python/apache_beam/pipeline.py:851

              current.add_output(pc, tag)
          continue

        # If there is already a tag with the same name, increase a counter for
        # the name. This can happen, for example, when a composite outputs a
        # list of PCollections where all the tags are None.
        base = tag
        counter = 0
        while tag in current.outputs:
          counter += 1
          tag = '%s_%d' % (base, counter)

        current.add_output(result, tag)

      if (type_options is not None and
          type_options.type_check_strictness == 'ALL_REQUIRED' and
          transform.get_type_hints().output_types is None):
        ptransform_name = '%s(%s)' % (transform.__class__.__name__, full_label)
        raise TypeCheckError(
            'Pipeline type checking is enabled, however no '
            'output type-hint was found for the '
            'PTransform %s' % ptransform_name)
    finally:
      self.transforms_stack.pop()
    return pvalueish_result

  def _assert_not_applying_PDone(
      self,
      pvalueish: Optional[pvalue.PValue],
      transform: ptransform.PTransform):
    if isinstance(pvalueish, pvalue.PDone) and isinstance(transform, ParDo):
      # If the input is a PDone, we cannot apply a ParDo transform.
      full_label = self._current_transform().full_label
      producer_label = pvalueish.producer.full_label
      raise TypeCheckError(
          f'Transform "{full_label}" was applied to the output of '
          f'"{producer_label}" but "{producer_label.split("/")[-1]}" '

View on GitHub (pinned to 12126d8942)

Solutions

  1. Remove the extra .apply() after the write/sink transform and apply further transforms to the PCollection before writing
  2. Capture the PCollection before the sink if you need to apply more transforms to the same data
  3. If you truly need a downstream effect, wrap logic in the DoFn itself rather than applying a transform to PDone

Example fix

// before
_ = (pcoll | 'Write' >> beam.io.WriteToText('out') | 'More' >> beam.Map(fn))
// after
transformed = pcoll | 'More' >> beam.Map(fn)
transformed | 'Write' >> beam.io.WriteToText('out')
Defensive patterns

Strategy: validation

Validate before calling

if isinstance(producer_result, apache_beam.pvalue.PDone):
    raise ValueError('Cannot apply a transform to a PDone output')

Type guard

from apache_beam.pvalue import PValue

def is_pcollection(x):
    return isinstance(x, PValue) and not isinstance(x, type(__import__('apache_beam').pvalue.PDone)())

Try / catch

try:
    result = pdone | beam.Map(fn)
except apache_beam.TypeCheckError as e:
    logging.error('Cannot chain transform after sink: %s', e)

Prevention

When it happens

Trigger: Calling pipeline.apply(some_par_do, pdone_value) where pdone_value is the result of a transform returning PDone, e.g. writing to a sink or calling custom_write().apply(...) chain after a write.

Common situations: Chaining a .apply() onto the result of a WriteToText/WriteToBigQuery (which yields PDone); mistakenly treating the return of pipeline.run() or a sink write as a PCollection.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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