{"record":{"id":"4800bc46275b43dd","repo":"apache/beam","slug":"expected-data-to-be-dicts-got-type-batch-0-instead","errorCode":null,"errorMessage":"Expected data to be dicts, got {type(batch[0])} instead.","messagePattern":"Expected data to be dicts, got (.+?) instead\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/ml/transforms/base.py","lineNumber":192,"sourceCode":"  \"\"\"\n  Only for internal use. No backwards compatibility guarantees.\n  \"\"\"\n  @abc.abstractmethod\n  def append_transform(self, transform: BaseOperation):\n    \"\"\"\n    Append transforms to the ProcessHandler.\n    \"\"\"\n\n\ndef _dict_input_fn(\n    columns: Sequence[str], batch: Sequence[Union[dict[str, Any],\n                                                  beam.Row]]) -> list[str]:\n  \"\"\"Extract text from specified columns in batch.\"\"\"\n  if batch and hasattr(batch[0], '_asdict'):\n    batch = [row._asdict() if hasattr(row, '_asdict') else row for row in batch]\n\n  if not batch or not isinstance(batch[0], dict):\n    raise TypeError(\n        'Expected data to be dicts, got '\n        f'{type(batch[0])} instead.')\n  result = []\n  expected_keys = set(batch[0].keys())\n  expected_columns = set(columns)\n  # Process one batch item at a time\n  for item in batch:\n    item_keys = item.keys() if isinstance(item, dict) else set()\n    if set(item_keys) != expected_keys:\n      extra_keys = item_keys - expected_keys\n      missing_keys = expected_keys - item_keys\n      raise RuntimeError(\n          f'All dicts in batch must have the same keys. '\n          f'extra keys: {extra_keys}, '\n          f'missing keys: {missing_keys}')\n    missing_columns = expected_columns - item_keys\n    if (missing_columns):\n      raise RuntimeError(","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/ml/transforms/base.py#L174-L210","documentation":"_dict_input_fn extracts text from batches whose elements must be dicts (beam.Row objects are converted via _asdict first). If the first element of a non-empty batch is not a dict, a TypeError is raised because column-based extraction cannot proceed.","triggerScenarios":"Passing a PCollection of namedtuples without _asdict support, plain strings, lists, or dataclass instances to MLTransform without specifying columns compatible with dict/Row inputs.","commonSituations":"Feeding raw string documents into MLTransform; applying a transform that expects dict input to a pipeline emitting typed rows or objects; forgetting to add a beam.Map(lambda x: x._asdict()) step.","solutions":["Convert your elements to dicts before MLTransform, e.g. beam.Map(lambda x: {'text': x}).","If emitting beam.Row, ensure elements are actual Row objects so _asdict conversion applies.","Check the transform's expected input type and use the appropriate type_adapter (MLTransform columns/type_adapter)."],"exampleFix":"// before\nbeam.Create(['hello', 'world']) | MLTransform(write_artifact_location=..., transforms=[...])\n// after\nbeam.Create(['hello', 'world']) | beam.Map(lambda s: {'text': s}) | MLTransform(...)","handlingStrategy":"type-guard","validationCode":"sample = next(iter(pcoll), None)\nassert sample is None or isinstance(sample, dict) or hasattr(sample, '_asdict'), 'MLTransform needs dict/Row input'","typeGuard":"def is_dict_batch(batch) -> bool:\n    return not batch or isinstance(batch[0], dict)","tryCatchPattern":"try:\n    out = data | MLTransform(...)\nexcept TypeError as e:\n    if 'Expected data to be dicts' in str(e):\n        data = data | beam.Map(lambda x: x._asdict() if hasattr(x, '_asdict') else {'text': x})\n        out = data | MLTransform(...)","preventionTips":["Always beam.Map raw values into dicts with your expected keys before MLTransform","Emit beam.Row for structured data so _asdict conversion works","Unit-test the element type at the MLTransform boundary"],"tags":["python","apache-beam","type-mismatch"],"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"}