apache/beam · error · IllegalArgumentException
DLQ Router only supports PCollectionTuples split between…
Error message
DLQ Router only supports PCollectionTuples split between two message groupings
What it means
DLQRouter.expand() requires a PCollectionTuple containing exactly the two configured TupleTags — the 'good' messages tag and the 'bad' (dead-letter) messages tag. If any additional TupleTag/PCollection is present in the tuple (after removing the two known tags), it throws IllegalArgumentException because the router has no destination for extra outputs.
Solutions
- Build a dedicated PCollectionTuple containing only the goodMessages and badMessages tags before expanding the router.
- Route any extra output PCollections to other sinks separately instead of passing them through the DLQRouter.
- Verify the TupleTag instances passed to DLQRouter.of(...) are exactly the ones used to build the tuple (same tag objects/ids).
Example fix
// before PCollectionTuple tuple = PCollectionTuple.of(good, goodPc).and(bad, badPc).and(metrics, metricsPc); dLQRouter.expand(tuple); // throws // after PCollectionTuple tuple = PCollectionTuple.of(good, goodPc).and(bad, badPc); dLQRouter.expand(tuple);
Defensive patterns
Strategy: validation
Validate before calling
Map<TupleTag<?>, PCollection<?>> tags = tuple.getAll();
if (tags.size() != 2 || !tags.containsKey(goodTag) || !tags.containsKey(badTag)) {
throw new IllegalArgumentException("DLQRouter tuple must contain exactly good and bad tags");
} Try / catch
try {
dlqRouter.expand(tuple);
} catch (IllegalArgumentException e) {
// rebuild a two-tag PCollectionTuple and retry the expansion
} Prevention
- Build a fresh PCollectionTuple with only the good/bad tags for the router.
- Send extra outputs (metrics, retries) through their own sinks.
- Reuse the exact same TupleTag instances the router was constructed with.
When it happens
Trigger: Applying DLQRouter.expand() to a PCollectionTuple that was built with more than two tags, e.g. one that also carries metrics, retry, or side-output PCollections from a multi-output transform.
Common situations: Wiring the DLQ router downstream of a ParDo producing multiple output tags, or reusing a shared PCollectionTuple that accumulated extra keys instead of constructing a fresh two-tag tuple for the router.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Failed to validate transform
- Pipeline update will not be possible because the following…
- strictness check failed
- Compression factor should be greater than 0.
- Delimiter must be a non-empty bytes sequence.
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/aba6836e4a897775.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/io/components/src/main/java/org/apache/beam/sdk/io/components/deadletterqueue/DLQRouter.java:53
private final PTransform<@NonNull PCollection<K>, ?> errorSink;
public DLQRouter(
TupleTag<T> goodMessages,
TupleTag<K> badMessages,
PTransform<@NonNull PCollection<K>, ?> errorSink) {
this.goodMessages = goodMessages;
this.badMessages = badMessages;
this.errorSink = errorSink;
}
@Override
public PCollection<T> expand(@NonNull PCollectionTuple input) {
// validate no extra messages are dropped
Map<TupleTag<?>, PCollection<?>> pcollections = new HashMap<>(input.getAll());
pcollections.remove(goodMessages);
pcollections.remove(badMessages);
if (pcollections.size() != 0) {
throw new IllegalArgumentException(
"DLQ Router only supports PCollectionTuples split between two message groupings");
}
input.get(badMessages).apply(errorSink);
return input.get(goodMessages);
}
}
View on GitHub (pinned to 12126d8942)