apache/beam · error · java.lang.IllegalArgumentException
Found conflicting TupleTags in flattened expansion of
Error message
Found conflicting TupleTags in flattened expansion of <partiallyExpanded>: <key> maps to <previous> and <value>
What it means
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.
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.
Example fix
// before
TupleTag<String> out = new TupleTag<String>("out") {};
TupleTag<Integer> other = new TupleTag<Integer>("out") {}; // same tag id -> conflict
// after
TupleTag<String> out = new TupleTag<String>("out") {};
TupleTag<Integer> other = new TupleTag<Integer>("outInt") {}; Defensive patterns
Strategy: validation
Validate before calling
Set<String> seen = new HashSet<>();
for (TupleTag<?> tag : outputsMap.keySet()) {
if (!seen.add(tag.getId())) throw new IllegalStateException("duplicate TupleTag: " + tag.getId());
} Try / catch
try {
PCollectionTuple pct = composite.expand();
PValues.expandOutput(...);
} catch (IllegalArgumentException e) {
throw new IllegalStateException("Composite transform reuses a TupleTag: " + e.getMessage(), e);
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- A PValue contained in
- Non PCollection PValue that expands into itself
- TupleTag already present in this tuple
- A function must be provided to convert the input type into…
- A schema was provided without a data format (or viceversa)…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/59735559b9ee4a80.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/values/PValues.java:64
* <li>{@link POutput#expand} (users can write custom POutputs)
* <li>{@link PInput#expand} (users can write custom PInputs)
* <li>{@link PTransform#getAdditionalInputs} (users can have their composites report inputs not
* passed by {@link PCollection#apply})
* </ul>
*
* <p>These all return {@code Map<TupleTag<?> PValue>}. A user's implementation of these methods
* is permitted to return either a {@link PCollection} or a {@link PCollectionView} for each
* PValue. PCollection's expand to themselves and {@link PCollectionView} expands to the {@link
* PCollection} that it is a view of.
*/
public static Map<TupleTag<?>, PCollection<?>> fullyExpand(
Map<TupleTag<?>, PValue> partiallyExpanded) {
Map<TupleTag<?>, PCollection<?>> result = new LinkedHashMap<>();
for (Map.Entry<TupleTag<?>, PValue> pvalue : partiallyExpanded.entrySet()) {
if (pvalue.getValue() instanceof PCollection) {
PCollection<?> previous = result.put(pvalue.getKey(), (PCollection<?>) pvalue.getValue());
if (previous != null) {
throw new IllegalArgumentException(
String.format(
"Found conflicting %ss in flattened expansion of %s: %s maps to %s and %s",
partiallyExpanded,
TupleTag.class.getSimpleName(),
pvalue.getKey(),
previous,
pvalue.getValue()));
}
} else {
if (pvalue.getValue().expand().size() == 1
&& Iterables.getOnlyElement(pvalue.getValue().expand().values())
.equals(pvalue.getValue())) {
throw new IllegalStateException(
String.format(
"Non %s %s that expands into itself %s",
PCollection.class.getSimpleName(),
PValue.class.getSimpleName(),
pvalue.getValue()));View on GitHub (pinned to 12126d8942)