apache/beam · error · ValueError
Return value not iterable: %s: %s
Error message
Return value not iterable: %s: %s
What it means
DoFn.default_type_hints strips the outer iterable from the function's output type because ParDo/FlatMap semantics require the callable's return value to be iterable of elements (core.py:826). If strip_iterable() finds the inferred output type is not iterable, the ValueError is re-raised with the DoFn in the message.
Source
Thrown at sdks/python/apache_beam/transforms/core.py:826
if (process_batch_type_hints.output_types
!= typehints.decorators.IOTypeHints.empty().output_types):
if (process_type_hints.output_types
!= typehints.decorators.IOTypeHints.empty().output_types and
process_batch_type_hints.output_types
!= process_type_hints.output_types):
raise TypeError(
f"DoFn {self!r} yields element from both process and "
"process_batch, but they have mismatched output typehints:\n"
f" process: {process_type_hints.output_types}\n"
f" process_batch: {process_batch_type_hints.output_types}")
process_type_hints = process_type_hints.with_output_types_from(
process_batch_type_hints)
try:
process_type_hints = process_type_hints.strip_iterable()
except ValueError as e:
raise ValueError('Return value not iterable: %s: %s' % (self, e))
process_type_hints = process_type_hints.extract_tagged_outputs()
# Prefer class decorator type hints for backwards compatibility.
return get_type_hints(self.__class__).with_defaults(process_type_hints)
# TODO(sourabhbajaj): Do we want to remove the responsibility of these from
# the DoFn or maybe the runner
def infer_output_type(self, input_type):
# TODO(https://github.com/apache/beam/issues/19824): Side inputs types.
return trivial_inference.element_type(
_strip_output_annotations(
trivial_inference.infer_return_type(self.process, [input_type])))
@property
def _process_defined(self) -> bool:
# Check if this DoFn's process method has been overridden
# Note that we retrieve the __func__ attribute, if it exists, to get the
# underlying function from the bound method.View on GitHub (pinned to 12126d8942)
Solutions
- Annotate the method with an iterable output type, e.g. -> Iterator[str] or -> Iterable[List[int]].
- Use `yield` in `process` so the inferred type is a generator (iterable).
- If the method intentionally returns a scalar, wrap it or restructure to yield.
Example fix
# before
class MyDoFn(DoFn):
def process(self, x) -> str:
return str(x)
# after
class MyDoFn(DoFn):
def process(self, x) -> Iterator[str]:
yield str(x) Defensive patterns
Strategy: validation
Validate before calling
import inspect
from apache_beam.typehints import typehints
def check_iterable_return(fn):
ret = inspect.signature(fn).return_annotation
if ret is not inspect.Signature.empty and not str(ret).startswith(('Iterator', 'Iterable', 'Generator', 'List', 'list')):
raise TypeError(f'{fn.__name__} should have an iterable return annotation, got {ret}') Type guard
def yields_elements(fn) -> bool:
import inspect
return any('yield' in getattr(c, 'co_code', b'').decode('latin1', 'ignore') for c in inspect.unwrap(fn).__code__.co_consts if hasattr(c, 'co_code')) Try / catch
try:
hints = dofn.default_type_hints()
except ValueError as e:
if 'Return value not iterable' in str(e):
logger.error('process must yield/return an iterable: %s', e)
raise Prevention
- Always use `yield` in process methods rather than `return`
- Annotate process/process_batch returns as Iterator[T] or Iterable[T]
- Run pipeline type-checking in unit tests (assert_that with output verification)
When it happens
Trigger: A `process`/`process_batch` method whose annotated or inferred return type is a non-iterable, e.g. annotated `-> int` or `-> str` when Beam expects Iterator/Iterable of elements.
Common situations: Using `return` instead of `yield` with a scalar; explicit output annotations like `-> str`; wrappers returning single values instead of generators.
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
- Unable to deterministically encode '%s' of type '%s', please
- document_field cannot be empty
- Expected text content in {type(item).__name__} {item.id}, go
- Expected image content in {type(item).__name__} {item.id}, g
- Pipeline type checking is enabled, however no output type-hi
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/3f43bff33955c971.
Report an issue: GitHub.