{"record":{"id":"f5e626111e7c135a","repo":"apache/beam","slug":"pardo-must-be-called-with-a-dofn-instance","errorCode":null,"errorMessage":"ParDo must be called with a DoFn instance.","messagePattern":"ParDo must be called with a DoFn instance\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/transforms/core.py","lineNumber":1581,"sourceCode":"    *args: positional arguments passed to the :class:`DoFn` object.\n    **kwargs:  keyword arguments passed to the :class:`DoFn` object.\n\n  Note that the positional and keyword arguments will be processed in order\n  to detect :class:`~apache_beam.pvalue.PCollection` s that will be computed as\n  side inputs to the transform. During pipeline execution whenever the\n  :class:`DoFn` object gets executed (its :meth:`DoFn.process()` method gets\n  called) the :class:`~apache_beam.pvalue.PCollection` arguments will be\n  replaced by values from the :class:`~apache_beam.pvalue.PCollection` in the\n  exact positions where they appear in the argument lists.\n  \"\"\"\n  def __init__(self, fn, *args, **kwargs):\n    super().__init__(fn, *args, **kwargs)\n    # TODO(robertwb): Change all uses of the dofn attribute to use fn instead.\n    self.dofn = self.fn\n    self.output_tags = set()  # type: typing.Set[str]\n\n    if not isinstance(self.fn, DoFn):\n      raise TypeError('ParDo must be called with a DoFn instance.')\n\n    # DoFn.process cannot allow both return and yield\n    if _check_fn_use_yield_and_return(self.fn.process):\n      _LOGGER.warning(\n          'Using yield and return in the process method '\n          'of %s can lead to unexpected behavior, see:'\n          'https://github.com/apache/beam/issues/22969.',\n          self.fn.__class__)\n\n    # Validate the DoFn by creating a DoFnSignature\n    from apache_beam.runners.common import DoFnSignature\n    self._signature = DoFnSignature(self.fn)\n\n  def with_exception_handling(\n      self,\n      main_tag='good',\n      dead_letter_tag='bad',\n      *,","sourceCodeStart":1563,"sourceCodeEnd":1599,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/transforms/core.py#L1563-L1599","documentation":" beam.ParDo (and its subclasses like FlatMap/Map wrappers) requires the fn argument to be an instance of DoFn. Passing a plain function or other object causes this TypeError because ParDo relies on DoFn process/ lifecycle methods.","triggerScenarios":"ParDo(my_plain_function) called directly instead of ParDo(DoFn subclass instance); passing a lambda or builtin to ParDo; constructing ParDo in a custom runner code path.","commonSituations":"Users porting from Map/FlatMap (which wrap callables) to ParDo without subclassing DoFn; refactoring where a DoFn instance was replaced with a bare function; custom transforms that misuse ParDo internally.","solutions":["Subclass DoFn and pass an instance: class MyDoFn(beam.DoFn): def process(self, x): yield x; then beam.ParDo(MyDoFn()).","If you only have a callable, use beam.FlatMap / beam.Map (they wrap callables via _CallableWrapperDoFn) instead of ParDo directly.","Check that the variable is not None or a function; isinstance(fn, beam.DoFn) guard.","If migrating code, convert the function into a DoFn with @beam.DoFn.process or keep using Map/FlatMap.","Example fix: `p | beam.ParDo(MyDoFn())` with `class MyDoFn(beam.DoFn)` instead of `p | beam.ParDo(lambda x: x)`."],"exampleFix":"// before\npcoll | beam.ParDo(lambda x: [x, x])\n// after\nclass DuplicateDoFn(beam.DoFn):\n    def process(self, x):\n        yield x\n        yield x\npcoll | beam.ParDo(DuplicateDoFn())","handlingStrategy":"type-guard","validationCode":"if not isinstance(fn, beam.DoFn):\n    raise TypeError('ParDo requires a DoFn instance; use beam.Map/FlatMap for plain callables')","typeGuard":"def is_dofn(x) -> bool:\n    return isinstance(x, beam.DoFn)","tryCatchPattern":null,"preventionTips":["Use beam.Map/beam.FlatMap for plain callables and lambdas.","Reserve beam.ParDo for DoFn subclasses and instantiate them.","Add isinstance checks in custom transform wrappers that forward fn to ParDo."],"tags":["python","apache-beam","pardo","dofn"],"backgroundTag":"invalid-argument-value","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}