{"record":{"id":"63fbd2e347d09119","repo":"apache/beam","slug":"element-types-has-different-number-of-fields","errorCode":null,"errorMessage":"element types has different number of fields","messagePattern":"element types has different number of fields","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/typehints/schemas.py","lineNumber":731,"sourceCode":"        \"https://s.apache.org/beam-python-schemas\")\n\n\ndef named_fields_from_element_type(\n    element_type: type) -> List[Tuple[str, type]]:\n  return named_fields_from_schema(schema_from_element_type(element_type))\n\n\ndef union_schema_type(element_types):\n  \"\"\"Returns a schema whose fields are the union of each corresponding field.\n\n  element_types must be a set of schema-aware types whose fields have the\n  same naming and ordering.\n  \"\"\"\n  named_fields_and_types = []\n  for t in element_types:\n    n = named_fields_from_element_type(t)\n    if named_fields_and_types and len(named_fields_and_types[-1]) != len(n):\n      raise TypeError(\"element types has different number of fields\")\n    named_fields_and_types.append(n)\n\n  union_fields_and_types = []\n  for field in zip(*named_fields_and_types):\n    names, types = zip(*field)\n    name_set = set(names)\n    if len(name_set) != 1:\n      raise TypeError(\n          f\"Could not determine schema for type hints {element_types!r}: \"\n          f\"Inconsistent names: {name_set}\")\n    union_fields_and_types.append(\n        (next(iter(name_set)), typehints.Union[types]))\n  return named_tuple_from_schema(named_fields_to_schema(union_fields_and_types))\n\n\nclass _Ephemeral:\n  \"\"\"Helper class for wrapping unpicklable objects.\"\"\"\n  def __init__(self, obj):","sourceCodeStart":713,"sourceCodeEnd":749,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/typehints/schemas.py#L713-L749","documentation":"apache_beam's union_schema_type() builds a schema for a Union of named-tuple-like element types by requiring every element type to have the same number of fields. Before zipping fields across element types it compares each type's field count with the previous one's and raises TypeError when they differ. This guards against silently producing a malformed union schema.","triggerScenarios":"Calling union_schema_type() (directly or via schema coercion of typing.Union[...]) with element types such as typing.NamedTuple classes or beam Rows that declare different numbers of fields, e.g. Union[Row(a=int), Row(a=int, b=str)] or Union[NamedTupleA(x,y), NamedTupleB(x)].","commonSituations":"Evolving a NamedTuple class in one place but not another version of the pipeline; mixing a dataclass/Row and a NamedTuple with different arity in a Union annotation on a PTransform; generating schemas from type hints after a schema migration changed field count.","solutions":["Make every element type in the Union have the same number of fields with identical names and ordering.","Remove the mismatched type from the Union, or widen the narrower type to match the wider one.","Convert the types to a common schema explicitly (e.g. use beam.Row or a single NamedTuple) instead of relying on union schema inference."],"exampleFix":"// before\nclass EventV1(NamedTuple):\n  id: int\n\nclass EventV2(NamedTuple):\n  id: int\n  ts: str\n\n# Union[EventV1, EventV2] -> TypeError\n\n// after\nclass EventV1(NamedTuple):\n  id: int\n  ts: Optional[str] = None\n\nclass EventV2(NamedTuple):\n  id: int\n  ts: str\n\n# Union[EventV1, EventV2]","handlingStrategy":"validation","validationCode":"from typing import get_type_hints, NamedTuple\n\ndef check_same_field_count(types):\n    counts = {len(t._fields) if issubclass(t, tuple) else None for t in types}\n    if None in counts or len(counts) != 1:\n        raise TypeError(\"Union element types must have equal field counts\")","typeGuard":"def same_arity(types):\n    return len(types) > 0 and all(hasattr(t, '_fields') and len(t._fields) == len(types[0]._fields) for t in types)","tryCatchPattern":"try:\n    schema = union_schema_type(element_types)\nexcept TypeError as e:\n    if \"different number of fields\" in str(e):\n        schema = None  # fall back to a common row schema\n    else:\n        raise","preventionTips":["Keep union member NamedTuples derived from one shared base class so field sets stay in sync.","Add a unit test that builds the Union schema for every record-type combination you emit.","When evolving schemas, update all versions of a record type together."],"tags":["python","apache-beam","schema","type-hints","union"],"backgroundTag":"schema-validation-failed","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"}