{"record":{"id":"b3b7734577fdfa3c","repo":"apache/beam","slug":"non-pcollection-pvalue-that-expands-into-itself-value","errorCode":null,"errorMessage":"Non PCollection PValue that expands into itself <value>","messagePattern":"Non PCollection PValue that expands into itself <value>","errorType":"exception","errorClass":"java.lang.IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/values/PValues.java","lineNumber":77,"sourceCode":"    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()));\n        }\n        /* At this point we know it is a PCollectionView or some internal hacked PValue. To be\n        liberal, we\n        allow it to expand into any number of PCollections, but do not allow structures that\n        require\n        further recursion. */\n        for (Map.Entry<TupleTag<?>, PValue> valueComponent :\n            pvalue.getValue().expand().entrySet()) {\n          if (!(valueComponent.getValue() instanceof PCollection)) {\n            throw new IllegalStateException(\n                String.format(\n                    \"A %s contained in %s expanded to a non-%s: %s\",\n                    PValue.class.getSimpleName(),","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/values/PValues.java#L59-L95","documentation":"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.","triggerScenarios":"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.","commonSituations":"Custom composite PTransform implementations returning this/wrong field from expand(); a PValueBase subclass that forgot to expand into its actual underlying PCollections.","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)."],"exampleFix":"// before\n@Override\npublic Map<TupleTag<?>, PValue> expand() {\n  return Collections.singletonMap(tag, this); // expands into itself, non-PCollection\n}\n// after\n@Override\npublic Map<TupleTag<?>, PValue> expand() {\n  return Collections.singletonMap(tag, underlyingPCollection);\n}","handlingStrategy":"try-catch","validationCode":"Map<TupleTag<?>, PValue> exp = value.expand();\nif (exp.size() == 1 && exp.values().iterator().next() == value && !(value instanceof PCollection)) {\n  throw new IllegalStateException(\"expand() must return underlying PCollections, not itself\");\n}","typeGuard":"static boolean expandsToSelf(PValue v) {\n  Map<TupleTag<?>, PValue> e = v.expand();\n  return e.size() == 1 && Iterables.getOnlyElement(e.values()).equals(v);\n}","tryCatchPattern":"try {\n  result = PValues.expandOutput(...);\n} catch (IllegalStateException e) {\n  throw new IllegalArgumentException(\"Custom PValue expands into itself; fix expand()\", e);\n}","preventionTips":["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."],"tags":["java","apache-beam","pvalue-expansion","illegal-state","infinite-recursion"],"backgroundTag":"internal-invariant-violation","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"}