{"record":{"id":"23800b1b6d46258b","repo":"apache/beam","slug":"expected-single-output-type-hint-for-s-but-got-s","errorCode":null,"errorMessage":"Expected single output type hint for %s but got: %s","messagePattern":"Expected single output type hint for (.+?) but got: (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/typehints/decorators.py","lineNumber":398,"sourceCode":"  def with_output_types(self, *args, **kwargs) -> 'IOTypeHints':\n    return self._replace(\n        output_types=(args, kwargs), origin=self._make_origin([self]))\n\n  def with_input_types_from(self, other: 'IOTypeHints') -> 'IOTypeHints':\n    return self._replace(\n        input_types=other.input_types, origin=self._make_origin([self]))\n\n  def with_output_types_from(self, other: 'IOTypeHints') -> 'IOTypeHints':\n    return self._replace(\n        output_types=other.output_types, origin=self._make_origin([self]))\n\n  def simple_output_type(self, context):\n    if self._has_output_types():\n      args, _ = self.output_types\n      # Note: kwargs may contain tagged output types, which are ignored here.\n      # Use tagged_output_types() to access those.\n      if len(args) != 1:\n        raise TypeError(\n            'Expected single output type hint for %s but got: %s' %\n            (context, self.output_types))\n      return args[0]\n\n  def tagged_output_types(self):\n    if not self._has_output_types():\n      return {}\n    _, tagged_output_types = self.output_types\n    return tagged_output_types\n\n  def has_simple_output_type(self):\n    \"\"\"Whether there's a single positional output type.\"\"\"\n    return (self.output_types and len(self.output_types[0]) == 1)\n\n  def strip_pcoll(self):\n    from apache_beam.pipeline import Pipeline\n    from apache_beam.pvalue import PBegin\n    from apache_beam.pvalue import PDone","sourceCodeStart":380,"sourceCodeEnd":416,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/typehints/decorators.py#L380-L416","documentation":"simple_output_type enforces that a function/transform has exactly one untagged output type hint. When the registered output_types tuple contains zero or multiple positional output types, Beam cannot return a single hint, so it raises TypeError listing the full output_types value.","triggerScenarios":"Declaring @with_output_types(int, str) (two positional hints) or with no positional hint but only kwargs, then something calls simple_output_type(context) expecting one return type, e.g. during pipeline type inference of a DoFn or PTransform.","commonSituations":"Multi-output transforms annotated with several positional types instead of a Tuple; a transform whose outputs are all tagged so positional args list is empty; copying an annotation pattern from a different transform.","solutions":["Use a single positional type: @with_output_types(Tuple[int, str]) instead of @with_output_types(int, str)","If outputs are tagged, access them via tagged_output_types() rather than simple_output_type","If there are genuinely multiple independent outputs, model them as Tuple or a dict of tags","Inspect self.output_types to confirm how many positional args were registered"],"exampleFix":"// before\n@with_output_types(int, str)\ndef parse(x): ...\n// after\nfrom apache_beam.typehints import Tuple\n@with_output_types(Tuple[int, str])\ndef parse(x): ...","handlingStrategy":"validation","validationCode":"def has_single_output(th):\n  args, _ = th.output_types\n  return len(args) == 1","typeGuard":null,"tryCatchPattern":"try:\n  out = th.simple_output_type(context)\nexcept TypeError:\n  out = th.tagged_output_types()  # fallback for tagged/multi-output","preventionTips":["One positional return type only; combine multiple into Tuple","Use tagged_output_types() for tagged outputs","Review output_types registration when copying decorators between transforms"],"tags":["python","type-hints","apache-beam"],"backgroundTag":"invalid-argument-value","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"}