{"record":{"id":"687b77d276370d02","repo":"apache/beam","slug":"tuple-input-to-s-must-have-two-components-found-s","errorCode":null,"errorMessage":"Tuple input to %s must have two components. Found %s.","messagePattern":"Tuple input to (.+?) must have two components\\. Found (.+?)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/typehints/typehints.py","lineNumber":1625,"sourceCode":"\ndef coerce_to_kv_type(element_type, label=None, side_input_producer=None):\n  \"\"\"Attempts to coerce element_type to a compatible kv type.\n\n  Raises an error on failure.\n  \"\"\"\n  if side_input_producer:\n    consumer = 'side-input of %r (producer: %r)' % (label, side_input_producer)\n  else:\n    consumer = '%r' % label\n\n  # If element_type is not specified, then treat it as `Any`.\n  if not element_type:\n    return KV[Any, Any]\n  elif isinstance(element_type, TupleHint.TupleConstraint):\n    if len(element_type.tuple_types) == 2:\n      return element_type\n    else:\n      raise ValueError(\n          \"Tuple input to %s must have two components. \"\n          \"Found %s.\" % (consumer, element_type))\n  elif isinstance(element_type, AnyTypeConstraint):\n    # `Any` type needs to be replaced with a KV[Any, Any] to\n    # satisfy the KV form.\n    return KV[Any, Any]\n  elif isinstance(element_type, UnionConstraint):\n    union_types = [coerce_to_kv_type(t) for t in element_type.union_types]\n    return KV[Union[tuple(t.tuple_types[0] for t in union_types)],\n              Union[tuple(t.tuple_types[1] for t in union_types)]]\n  else:\n    # TODO: Possibly handle other valid types.\n    raise ValueError(\n        \"Input to %s must be compatible with KV[Any, Any]. \"\n        \"Found %s.\" % (consumer, element_type))\n","sourceCodeStart":1607,"sourceCodeEnd":1641,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/typehints/typehints.py#L1607-L1641","documentation":"coerce_to_kv_type only accepts a 2-component TupleConstraint when coercing a hint into a KV type. A tuple hint with 1 or 3+ components cannot represent a key/value pair, so Beam raises. This happens during type inference for transforms like CombinePerKey, GroupByKey, or CoGroupByKey.","triggerScenarios":"Passing a PCollection of Tuple[int, str, bool] (or 1-tuples) into a KV-requiring transform, or calling coerce_to_kv_type(element_type, consumer) with such a hint.","commonSituations":"Emitting 3-field tuples from a DoFn then feeding GroupByKey/CombinePerKey; older Beam pipelines after moving from lambda returns of triples to KV transforms; accidental use of namedtuple with wrong arity.","solutions":["Emit exactly 2-tuples: pc | beam.Map(lambda x: (x.key, x.value)).","Use beam.KV(K, V) / Tuple[Tuple[K, V]] type hints so inference fails early and clearly.","Restructure: pack extra fields into the value, e.g. (k, (v, extra)) instead of (k, v, extra).","If you don't need keying, use a non-KV transform such as beam.CombineGlobally with a custom combiner."],"exampleFix":"// before\npc | beam.CombinePerKey(sum)  # elements are (k, v, extra)\n// after\npc | beam.Map(lambda x: (x[0], (x[1], x[2]))) | beam.CombinePerKey(my_fn)","handlingStrategy":"validation","validationCode":"from apache_beam.typehints import Tuple\nif not (isinstance(hint, tuple) or (hasattr(hint, 'tuple_types') and len(hint.tuple_types) == 2)):\n    raise TypeError('KV transforms need 2-tuples')","typeGuard":"def is_kv_tuple(t) -> bool:\n    return isinstance(t, tuple) and len(t) == 2","tryCatchPattern":"try:\n    kv = coerce_to_kv_type(element_type, consumer)\nexcept ValueError as e:\n    log.error('restructure PCollection to emit 2-tuples: %s', e)\n    raise","preventionTips":["Always emit (key, value) 2-tuples into keyed transforms","Use with_output_types(Tuple[K, V]) for early, clear failures","Pack extra fields into the value component rather than widening the tuple"],"tags":["python","apache-beam","type-hints","kv"],"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"}