{"record":{"id":"59735559b9ee4a80","repo":"apache/beam","slug":"found-conflicting-tupletags-in-flattened-expansion-of","errorCode":null,"errorMessage":"Found conflicting TupleTags in flattened expansion of <partiallyExpanded>: <key> maps to <previous> and <value>","messagePattern":"Found conflicting TupleTags in flattened expansion of <partiallyExpanded>: <key> maps to <previous> and <value>","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/values/PValues.java","lineNumber":64,"sourceCode":"   *   <li>{@link POutput#expand} (users can write custom POutputs)\n   *   <li>{@link PInput#expand} (users can write custom PInputs)\n   *   <li>{@link PTransform#getAdditionalInputs} (users can have their composites report inputs not\n   *       passed by {@link PCollection#apply})\n   * </ul>\n   *\n   * <p>These all return {@code Map<TupleTag<?> PValue>}. A user's implementation of these methods\n   * is permitted to return either a {@link PCollection} or a {@link PCollectionView} for each\n   * PValue. PCollection's expand to themselves and {@link PCollectionView} expands to the {@link\n   * PCollection} that it is a view of.\n   */\n  public static Map<TupleTag<?>, PCollection<?>> fullyExpand(\n      Map<TupleTag<?>, PValue> partiallyExpanded) {\n    Map<TupleTag<?>, PCollection<?>> result = new LinkedHashMap<>();\n    for (Map.Entry<TupleTag<?>, PValue> pvalue : partiallyExpanded.entrySet()) {\n      if (pvalue.getValue() instanceof PCollection) {\n        PCollection<?> previous = result.put(pvalue.getKey(), (PCollection<?>) pvalue.getValue());\n        if (previous != null) {\n          throw new IllegalArgumentException(\n              String.format(\n                  \"Found conflicting %ss in flattened expansion of %s: %s maps to %s and %s\",\n                  partiallyExpanded,\n                  TupleTag.class.getSimpleName(),\n                  pvalue.getKey(),\n                  previous,\n                  pvalue.getValue()));\n        }\n      } else {\n        if (pvalue.getValue().expand().size() == 1\n            && Iterables.getOnlyElement(pvalue.getValue().expand().values())\n                .equals(pvalue.getValue())) {\n          throw new IllegalStateException(\n              String.format(\n                  \"Non %s %s that expands into itself %s\",\n                  PCollection.class.getSimpleName(),\n                  PValue.class.getSimpleName(),\n                  pvalue.getValue()));","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/values/PValues.java#L46-L82","documentation":"PValues.fullyExpand() flattens a PValue's expansion tree into a Map<TupleTag, PCollection>. If two entries share the same TupleTag mapping to different PCollections, the flattened map would silently lose data, so Beam throws IllegalArgumentException. This indicates a composite transform returning duplicate TupleTags for distinct outputs.","triggerScenarios":"A multi-output composite PTransform (PTransform with PCollectionTuple/TupleTag outputs) reuses the same TupleTag for two different output PCollections, and the result is expanded via expandOutput/expandInput/expandValue.","commonSituations":"Defining TupleTag fields with identical default tags (e.g. new TupleTag<String>() {} declared twice with the same anonymous type); copying output maps manually; refactor merging two outputs into one tag.","solutions":["Give each output a distinct TupleTag (unique id: new TupleTag<String>(\"uniqueName\"){}`).","Check the composite transform's expand() to ensure each TupleTag maps to exactly one PCollection.","If outputs genuinely coincide, return a single PCollection instead of a multi-output mapping.","Rename duplicated TupleTag constants created by copy-paste."],"exampleFix":"// before\nTupleTag<String> out = new TupleTag<String>(\"out\") {};\nTupleTag<Integer> other = new TupleTag<Integer>(\"out\") {}; // same tag id -> conflict\n// after\nTupleTag<String> out = new TupleTag<String>(\"out\") {};\nTupleTag<Integer> other = new TupleTag<Integer>(\"outInt\") {};","handlingStrategy":"validation","validationCode":"Set<String> seen = new HashSet<>();\nfor (TupleTag<?> tag : outputsMap.keySet()) {\n  if (!seen.add(tag.getId())) throw new IllegalStateException(\"duplicate TupleTag: \" + tag.getId());\n}","typeGuard":null,"tryCatchPattern":"try {\n  PCollectionTuple pct = composite.expand();\n  PValues.expandOutput(...);\n} catch (IllegalArgumentException e) {\n  throw new IllegalStateException(\"Composite transform reuses a TupleTag: \" + e.getMessage(), e);\n}","preventionTips":["Use distinct named TupleTags per output (unique string ids).","Never copy-paste TupleTag declarations without renaming.","Unit-test multi-output transforms by expanding them in a TestPipeline."],"tags":["java","apache-beam","tupletag","pvalue-expansion","duplicate-key"],"backgroundTag":"duplicate-key","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"}