apache/beam · error · java.lang.IllegalStateException
Non PCollection PValue that expands into itself
Error message
Non PCollection PValue that expands into itself <value>
What it means
During full expansion of a PValue's outputs, a non-PCollection PValue whose expand() returns exactly itself is rejected with IllegalStateException. Such a value would recurse infinitely when flattened — an internal pipeline-construction invariant violation.
Solutions
- Fix the custom PValue's expand() to return the actual underlying PCollection(s), never itself.
- If the value is genuinely a PCollection, make its expand() map to itself as a PCollection (allowed) rather than as a non-PCollection PValue.
- Check that composite transforms return PCollections, not wrapper PValues, in their output maps.
- Report to Beam dev list if it occurs with built-in transforms (likely a bug).
Example fix
// before
@Override
public Map<TupleTag<?>, PValue> expand() {
return Collections.singletonMap(tag, this); // expands into itself, non-PCollection
}
// after
@Override
public Map<TupleTag<?>, PValue> expand() {
return Collections.singletonMap(tag, underlyingPCollection);
} Defensive patterns
Strategy: try-catch
Validate before calling
Map<TupleTag<?>, PValue> exp = value.expand();
if (exp.size() == 1 && exp.values().iterator().next() == value && !(value instanceof PCollection)) {
throw new IllegalStateException("expand() must return underlying PCollections, not itself");
} Type guard
static boolean expandsToSelf(PValue v) {
Map<TupleTag<?>, PValue> e = v.expand();
return e.size() == 1 && Iterables.getOnlyElement(e.values()).equals(v);
} Try / catch
try {
result = PValues.expandOutput(...);
} catch (IllegalStateException e) {
throw new IllegalArgumentException("Custom PValue expands into itself; fix expand()", e);
} Prevention
- Implement expand() to return concrete underlying PCollections.
- Never return `this` from a non-PCollection PValue's expand().
- Add a self-expansion unit test for custom PValue subclasses.
When it happens
Trigger: A custom PValue/PTransform whose expand() returns a map containing the value itself as its only expansion, then is passed through PValues.expandOutput/expandInput/expandValue.
Common situations: Custom composite PTransform implementations returning this/wrong field from expand(); a PValueBase subclass that forgot to expand into its actual underlying PCollections.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- A PValue contained in
- Cannot call getFromRowFunction when there is no schema
- Cannot call getSchema when there is no schema
- Cannot call getToRowFunction when there is no schema
- Error collections cannot be added after Error Handler is…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/b3b7734577fdfa3c.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/values/PValues.java:77
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()));
}
/* At this point we know it is a PCollectionView or some internal hacked PValue. To be
liberal, we
allow it to expand into any number of PCollections, but do not allow structures that
require
further recursion. */
for (Map.Entry<TupleTag<?>, PValue> valueComponent :
pvalue.getValue().expand().entrySet()) {
if (!(valueComponent.getValue() instanceof PCollection)) {
throw new IllegalStateException(
String.format(
"A %s contained in %s expanded to a non-%s: %s",
PValue.class.getSimpleName(),View on GitHub (pinned to 12126d8942)