apache/beam · error · IllegalArgumentException
TupleTag already present in this tuple
Error message
TupleTag already present in this tuple
What it means
PCollectionTuple.ofPrimitiveOutputsInternal builds its internal map of output tags to PCollections and throws IllegalArgumentException when the same TupleTag appears twice in the provided TupleTagList. Beam requires each output tag in a tuple to be unique so that tags can act as unambiguous keys for mapping outputs. This guard prevents silently overwriting or aliasing a tagged output.
Solutions
- Ensure each output in the PCollectionTuple uses a distinct TupleTag — create a new TupleTag for the second output instead of reusing the first.
- Review TupleTag equality: two TupleTag instances compare equal when constructed without an id only if same object; with explicit ids, duplicate id strings collide — use unique ids.
- If tags come from user config or a collection, validate uniqueness (e.g. by tag id) before building the PCollectionTuple.
Example fix
// before
TupleTag<String> out = new TupleTag<>("out");
PCollectionTuple.of(out, mainPc).and(out, sidePc); // throws
// after
TupleTag<String> outMain = new TupleTag<>("outMain");
TupleTag<String> outSide = new TupleTag<>("outSide");
PCollectionTuple.of(outMain, mainPc).and(outSide, sidePc); Defensive patterns
Strategy: validation
Validate before calling
Set<TupleTag<?>> seen = new HashSet<>();
for (TupleTag<?> tag : tags) {
if (!seen.add(tag)) throw new IllegalArgumentException("duplicate TupleTag: " + tag.getId());
} Prevention
- Declare one final TupleTag per side output in the DoFn, never reuse a tag for two outputs.
- Give every TupleTag an explicit unique id string when tags cross serialization boundaries.
- Validate tag collections for uniqueness before building PCollectionTuples in generated/config-driven pipelines.
When it happens
Trigger: Calling PCollectionTuple.ofPCollections / PCollectionTuple.of (which routes into ofPrimitiveOutputsInternal) with a TupleTagList or set of (tag, PCollection) pairs in which the same TupleTag instance or an equal TupleTag (same id) is supplied more than once, e.g. PCollectionTuple.of(tag1, pc1).and(tag1, pc2).
Common situations: Reusing a single TupleTag field for multiple outputs in a ParDo with several side outputs; programmatically generating tags in a loop but reusing one tag variable; copy-pasted multi-output pipeline code where a tag was meant to be a new TupleTag<> but was cloned.
Related errors
- ApproximateUnique.PerKey needs an estimation error between…
- Found conflicting TupleTags in flattened expansion of
- label + ": " + String.format(message, args)
- lenientFormat(errorMessageTemplate, p1, p2)
- must either have a non-empty list of PCollections, or must…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/0d10fb374e257933.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/values/PCollectionTuple.java:299
/**
* <b><i>For internal use only; no backwards-compatibility guarantees.</i></b>
*
* <p>Returns a {@link PCollectionTuple} with each of the given tags mapping to a new output
* {@link PCollection}.
*
* <p>For use by primitive transformations only.
*/
@Internal
public static PCollectionTuple ofPrimitiveOutputsInternal(
Pipeline pipeline,
TupleTagList outputTags,
Map<TupleTag<?>, Coder<?>> coders,
WindowingStrategy<?, ?> windowingStrategy,
IsBounded isBounded) {
Map<TupleTag<?>, PCollection<?>> pcollectionMap = new LinkedHashMap<>();
for (TupleTag<?> outputTag : outputTags.tupleTags) {
if (pcollectionMap.containsKey(outputTag)) {
throw new IllegalArgumentException("TupleTag already present in this tuple");
}
// In fact, `token` and `outputCollection` should have
// types TypeDescriptor<T> and PCollection<T> for some
// unknown T. It is safe to create `outputCollection`
// with type PCollection<Object> because it has the same
// erasure as the correct type. When a transform adds
// elements to `outputCollection` they will be of type T.
@SuppressWarnings("unchecked")
PCollection<?> outputCollection =
PCollection.createPrimitiveOutputInternal(
pipeline, windowingStrategy, isBounded, (Coder) coders.get(outputTag))
.setTypeDescriptor(outputTag.getTypeDescriptor());
pcollectionMap.put(outputTag, outputCollection);
}
return new PCollectionTuple(pipeline, pcollectionMap);
}View on GitHub (pinned to 12126d8942)