{"record":{"id":"c89520da743f837e","repo":"apache/beam","slug":"expected-outputtags-size-outputs-but-got-exactly-one","errorCode":null,"errorMessage":"Expected ${outputTags.size()} outputs, but got exactly one.","messagePattern":"Expected (.+?) outputs, but got exactly one\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/extensions/yaml/src/main/java/org/apache/beam/sdk/extensions/yaml/YamlTransform.java","lineNumber":185,"sourceCode":"    } else if (input instanceof PCollectionRowTuple) {\n      output = ((PCollectionRowTuple) input).apply(externalTransform);\n    } else {\n      throw new IllegalArgumentException(\"Unrecognized input type: \" + input);\n    }\n\n    if (outputTags == null) {\n      if (!(output instanceof PCollection)) {\n        throw new IllegalArgumentException(\n            \"Expected a single PCollection output, but got \"\n                + output\n                + \". Perhaps withMultipleOutputs() needs to be specified?\");\n      }\n      return (OutputT) output;\n    } else {\n      if (output instanceof PCollection) {\n        // ExternalPythonTransform always returns single outputs as PCollections.\n        if (outputTags.size() != 1) {\n          throw new IllegalArgumentException(\n              \"Expected \" + outputTags.size() + \" outputs, but got exactly one.\");\n        }\n        return (OutputT)\n            PCollectionRowTuple.of(outputTags.iterator().next(), (PCollection<Row>) output);\n      } else {\n        Map<TupleTag<?>, PValue> expandedOutputs = output.expand();\n        Set<String> actualOutputTags =\n            expandedOutputs.keySet().stream()\n                .map(TupleTag::getId)\n                .collect(Collectors.toCollection(HashSet::new));\n        if (!outputTags.equals(actualOutputTags)) {\n          throw new IllegalArgumentException(\n              \"Output has tags \"\n                  + Joiner.on(\", \").join(actualOutputTags)\n                  + \" but expected output tags \"\n                  + Joiner.on(\", \").join(outputTags));\n        }\n        PCollectionRowTuple result = PCollectionRowTuple.empty(input.getPipeline());","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/extensions/yaml/src/main/java/org/apache/beam/sdk/extensions/yaml/YamlTransform.java#L167-L203","documentation":"When outputTags are declared and the external transform returns a single PCollection, YamlTransform wraps it under one tag. If the declared outputTags count is not exactly 1, the single PCollection cannot satisfy the declared multi-output contract and IllegalArgumentException is thrown.","triggerScenarios":"Declaring 2+ output tags for a YamlTransform whose underlying external transform returns just one PCollection (single-output external transform paired with a multi-output spec).","commonSituations":"YAML spec over-declares outputs for a transform that was updated to emit only one; confusing single- and multi-output variants of the same Python transform.","solutions":["Declare exactly one output tag, or none, if the transform yields a single PCollection.","Fix the external transform to actually emit all declared outputs (use withMultipleOutputs).","Remove the extra declared output tags from the YAML spec.","Check the transform docs for the true number of outputs."],"exampleFix":"// before\n.withOutputTags(ImmutableList.of(new TupleTag<>(\"a\"), new TupleTag<>(\"b\")), ...)\n// after (transform emits one output)\n.withOutputTags(ImmutableList.of(new TupleTag<>(\"a\")), ...);","handlingStrategy":"validation","validationCode":"if (outputTags.size() > 1 && transformEmitsSinglePCollection) {\n  throw new IllegalStateException(\"Cannot declare \" + outputTags.size() + \" outputs for single-output transform\");\n}","typeGuard":"boolean outputCountMatches(int declared, Object out) { return declared == 1 || !(out instanceof PCollection); }","tryCatchPattern":"try {\n  return expand(input);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"outputs, but got exactly one\")) { /* fix output tag count */ }\n  throw e;\n}","preventionTips":["Declare outputTags count matching the transform's real output arity","Review external transform docs before multi-output specs","Add smoke tests for each YAML transform spec"],"tags":["apache-beam","java","yaml-transform","multiple-outputs"],"backgroundTag":"unexpected-response-shape","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"}