{"record":{"id":"7a7db4bc897f12ef","repo":"apache/beam","slug":"flatmap-and-pardo-must-return-an-iterable-s-was-returned","errorCode":null,"errorMessage":"FlatMap and ParDo must return an iterable. %s was returned instead.","messagePattern":"FlatMap and ParDo must return an iterable\\. (.+?) was returned instead\\.","errorType":"validation","errorClass":"TypeCheckError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/typehints/typecheck.py","lineNumber":118,"sourceCode":"          '%s' % (self.full_label, e))\n      _, _, tb = sys.exc_info()\n      raise TypeCheckError(error_msg).with_traceback(tb)\n    else:\n      return self._check_type(result)\n\n  @staticmethod\n  def _check_type(output):\n    if output is None:\n      return output\n\n    elif isinstance(output, (dict, bytes, str)):\n      object_type = type(output).__name__\n      raise TypeCheckError(\n          'Returning a %s from a ParDo or FlatMap is '\n          'discouraged. Please use list(\"%s\") if you really '\n          'want this behavior.' % (object_type, output))\n    elif not isinstance(output, abc.Iterable):\n      raise TypeCheckError(\n          'FlatMap and ParDo must return an '\n          'iterable. %s was returned instead.' % type(output))\n    return output\n\n\nclass TypeCheckWrapperDoFn(AbstractDoFnWrapper):\n  \"\"\"A wrapper around a DoFn which performs type-checking of input and output.\n  \"\"\"\n  def __init__(self, dofn, type_hints, label=None):\n    super().__init__(dofn)\n    self._process_fn = self.dofn._process_argspec_fn()\n    if type_hints.input_types:\n      input_args, input_kwargs = type_hints.input_types\n      self._input_hints = getcallargs_forhints(\n          self._process_fn, *input_args, **input_kwargs)\n    else:\n      self._input_hints = None\n    # TODO(robertwb): Multi-output.","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/typehints/typecheck.py#L100-L136","documentation":"Beam requires FlatMap/ParDo callables to return an iterable of output elements. _check_type raises TypeCheckError when the returned value is not iterable (after excluding None). This guarantees the runner can iterate the function's outputs.","triggerScenarios":"A FlatMap function returns a non-iterable such as an int, a custom object, or a single record object instead of a list/generator of records.","commonSituations":"Mixing up Map vs FlatMap semantics; a function that forgot to wrap its result in a list; returning a custom class that doesn't implement __iter__.","solutions":["Return a list/generator: return [result].","Use beam.Map (or ParDo with a DoFn yielding one element) when there is exactly one output per input.","Make the returned object iterable (implement __iter__) if it is a custom container.","Yield outputs instead of returning a single value."],"exampleFix":"// before\np | beam.FlatMap(lambda x: x * 2)  # returns int\n// after\np | beam.Map(lambda x: x * 2)","handlingStrategy":"validation","validationCode":"from collections.abc import Iterable\ndef ensure_iterable(out):\n    if out is None:\n        return []\n    if not isinstance(out, Iterable):\n        return [out]\n    return out","typeGuard":"def is_iterable_output(out) -> bool:\n    return out is None or isinstance(out, Iterable)","tryCatchPattern":"try:\n    outputs = fn(element)\nexcept TypeCheckError:\n    outputs = [fn(element)] if not isinstance(fn(element), Iterable) else []","preventionTips":["Remember FlatMap = N outputs, Map = 1 output; pick the right one","Always return list/generator from FlatMap callables","Add type hints so mismatches are caught at graph construction"],"tags":["python","apache-beam","flatmap","iterable"],"backgroundTag":"type-mismatch","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}