{"record":{"id":"6872046e4dd4836d","repo":"apache/beam","slug":"coder-for-the-groupbykey-operation-s-is-not-a-key-value","errorCode":null,"errorMessage":"Coder for the GroupByKey operation \"%s\" is not a key-value coder: %s.","messagePattern":"Coder for the GroupByKey operation \"(.+?)\" is not a key-value coder: (.+?)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/runners/dataflow/dataflow_runner.py","lineNumber":554,"sourceCode":"    \"\"\"Returns a coder based on a typehint object.\"\"\"\n    if window_coder:\n      return coders.WindowedValueCoder(\n          coders.registry.get_coder(typehint), window_coder=window_coder)\n    return coders.registry.get_coder(typehint)\n\n  def _verify_gbk_coders(self, transform, pcoll):\n    # Infer coder of parent.\n    #\n    # TODO(ccy): make Coder inference and checking less specialized and more\n    # comprehensive.\n\n    parent = pcoll.producer\n    if parent:\n      coder = parent.transform._infer_output_coder()  # pylint: disable=protected-access\n    if not coder:\n      coder = self._get_coder(pcoll.element_type or typehints.Any, None)\n    if not coder.is_kv_coder():\n      raise ValueError((\n          'Coder for the GroupByKey operation \"%s\" is not a '\n          'key-value coder: %s.') % (transform.label, coder))\n    # TODO(robertwb): Update the coder itself if it changed.\n    coders.registry.verify_deterministic(\n        coder.key_coder(), 'GroupByKey operation \"%s\"' % transform.label)\n\n  def get_default_gcp_region(self):\n    \"\"\"Get a default value for Google Cloud region according to\n    https://cloud.google.com/compute/docs/gcloud-compute/#default-properties.\n    If no default can be found, returns None.\n    \"\"\"\n    environment_region = os.environ.get('CLOUDSDK_COMPUTE_REGION')\n    if environment_region:\n      _LOGGER.info(\n          'Using default GCP region %s from $CLOUDSDK_COMPUTE_REGION',\n          environment_region)\n      return environment_region\n    try:","sourceCodeStart":536,"sourceCodeEnd":572,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/runners/dataflow/dataflow_runner.py#L536-L572","documentation":"Before submitting a GroupByKey, the DataflowRunner verifies that the coder for its input PCollection is a key-value (KV) coder and that the key coder is deterministic. A non-KV coder means the pipeline's type hints imply elements that aren't (key, value) pairs, so the shuffle cannot be encoded — a ValueError naming the GBK transform and the coder is raised.","triggerScenarios":"Running beam.GroupByKey() on a PCollection whose inferred/declared element type isn't KV[A,B] — e.g. applying GBK directly on a PCollection of scalars, or producing pairs via a transform whose output coder wasn't inferred as KV.","commonSituations":"Forgetting to Map to (key, value) pairs before GroupByKey; using lambdas/custom DoFns that erase type information; map side outputs with Any type hints.","solutions":["Map elements to KV pairs before the GBK: pairs = beam.Map(lambda x: (x['k'], x)).","Add explicit type hints, e.g. beam.Map(fn).with_output_types(types.KV[str, int]).","Check the producing transform's output coder with pipeline apply/inspect to confirm it's KV.","If keys use a non-deterministic coder, register a deterministic key coder or use a hashable/deterministic key representation."],"exampleFix":"// before\nresult = words | beam.GroupByKey()\n// after\nresult = (words\n    | beam.Map(lambda w: (w, 1)).with_output_types(typing.Tuple[str, int])\n    | beam.GroupByKey())","handlingStrategy":"validation","validationCode":"from apache_beam import typehints\nfrom apache_beam.coders import typecoders\ncoder = typecoders.registry.get_coder(pcoll.element_type or typehints.Any)\nassert coder.is_kv_coder(), 'PCollection fed to GroupByKey must be KV[A, B]'","typeGuard":null,"tryCatchPattern":"try:\n    result = pcoll | beam.GroupByKey()\nexcept ValueError as e:\n    if 'not a key-value coder' in str(e):\n        result = (pcoll | beam.Map(lambda x: (x['k'], x))) | beam.GroupByKey()","preventionTips":["Always Map to (key, value) tuples before GroupByKey","Add explicit with_output_types(typing.Tuple[K, V]) hints","Use type checkers: pipeline with type_check enabled to catch at construction"],"tags":["python","apache-beam","dataflow","groupbykey","coder"],"backgroundTag":"type-mismatch","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}