{"record":{"id":"fab0257004f2eedb","repo":"apache/beam","slug":"returning-a-s-from-a-pardo-or-flatmap-is-not-allowed-please","errorCode":null,"errorMessage":"Returning a %s from a ParDo or FlatMap is not allowed. Please use list(%r) if you really want this behavior.","messagePattern":"Returning a (.+?) from a ParDo or FlatMap is not allowed\\. Please use list\\(%r\\) if you really want this behavior\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/runners/common.py","lineNumber":1697,"sourceCode":"  def handle_process_outputs(\n      self, windowed_input_element, results, watermark_estimator=None):\n    # type: (WindowedValue, Iterable[Any], Optional[WatermarkEstimator]) -> None\n\n    \"\"\"Dispatch the result of process computation to the appropriate receivers.\n\n    A value wrapped in a TaggedOutput object will be unwrapped and\n    then dispatched to the appropriate indexed output.\n    \"\"\"\n    if self._check_user_dofn_output:\n      # This bug is deterministic per DoFn: if process() returns a\n      # str/bytes/dict once, it does so for every element. So we only need to\n      # validate the first output and can then disable the check to avoid\n      # per-element overhead (see\n      # https://github.com/apache/beam/issues/18712).\n      self._check_user_dofn_output = False\n      if isinstance(results, (str, bytes, dict)):\n        object_type = type(results).__name__\n        raise TypeError(\n            'Returning a %s from a ParDo or FlatMap is not allowed. '\n            'Please use list(%r) if you really want this behavior.' %\n            (object_type, results))\n\n    if results is None:\n      results = []\n\n    # TODO(https://github.com/apache/beam/issues/20404): Verify that the\n    #  results object is a valid iterable type if\n    #  performance_runtime_type_check is active, without harming performance\n    output_element_count = 0\n    for result in results:\n      tag, result = self._handle_tagged_output(result)\n\n      if not self._process_yields_batches:\n        # process yields elements\n        windowed_value = self._maybe_propagate_windowing_info(\n            windowed_input_element, result)","sourceCodeStart":1679,"sourceCodeEnd":1715,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/runners/common.py#L1679-L1715","documentation":"Apache Beam raises this TypeError from DoFnInvoker.handle_process_outputs when a user DoFn (ParDo/FlatMap) returns a str, bytes, or dict directly. Since these are iterable, Beam would otherwise silently treat them as a collection of outputs and iterate over them element by element, which is almost never what the user intended. The error forces you to make the intent explicit by wrapping the value in list(...).","triggerScenarios":"A DoFn's process() method (used via ParDo, FlatMap, or Map wrappers) executes `return some_string`, `return some_bytes`, or `return some_dict` instead of returning a list/iterable of elements or yielding.","commonSituations":"Returning a dict thinking it will pass through as a single element; returning a parsed JSON string from process(); writing `return line.strip()` in a FlatMap over lines, which returns a str; confusion between yield (element) and return (iterable of elements) semantics in Beam DoFns.","solutions":["Wrap the value in a list: `return [my_string]` / `return list(my_dict.items())` / `return [my_dict]` depending on whether the value should be one element or many.","Use `yield` instead of `return` so each element is emitted individually.","If you really want the str/bytes/dict iterated, make it explicit with `list(result)` as the message suggests."],"exampleFix":"// before\nclass ParseJson(beam.DoFn):\n    def process(self, element):\n        return json.loads(element)  # returns dict -> TypeError\n// after\nclass ParseJson(beam.DoFn):\n    def process(self, element):\n        yield json.loads(element)  # or: return [json.loads(element)]","handlingStrategy":"type-guard","validationCode":"def _is_valid_dofn_return(r):\n    return r is None or isinstance(r, (list, tuple, set, frozenset)) or (hasattr(r, '__iter__') and not isinstance(r, (str, bytes, dict)))","typeGuard":"def is_iterable_of_outputs(r):\n    return not isinstance(r, (str, bytes, dict)) and (r is None or hasattr(r, '__iter__'))","tryCatchPattern":"try:\n    out = fn.process(elem)\nexcept TypeError as e:\n    if 'ParDo or FlatMap is not allowed' in str(e):\n        out = list(fn.process(elem))\n    else:\n        raise","preventionTips":["Always yield or return a list from process(); never return a bare str/bytes/dict.","Add a unit test that runs the DoFn through beam.testing.util.assert_that on sample inputs.","Enable a lint rule or code review checklist flagging `return` of str/bytes/dict in DoFn.process."],"tags":["python","apache-beam","pardo","dofn","type-error"],"backgroundTag":"invalid-return-type","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"}