{"record":{"id":"b1eeb0decf889990","repo":"apache/beam","slug":"unable-to-parse-the-output-type-output-getclass-due-to-key","errorCode":null,"errorMessage":"Unable to parse the output type ${output.getClass()} due to key ${entry.getKey()} not mapping to a PCollection","messagePattern":"Unable to parse the output type (.+?) due to key (.+?) not mapping to a PCollection","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"sdks/java/expansion-service/src/main/java/org/apache/beam/sdk/expansion/service/TransformProvider.java","lineNumber":110,"sourceCode":"      return ((PCollectionTuple) output)\n          .getAll().entrySet().stream()\n              .collect(Collectors.toMap(entry -> entry.getKey().getId(), Map.Entry::getValue));\n    } else if (output instanceof PCollectionList<?>) {\n      PCollectionList<?> listOutput = (PCollectionList<?>) output;\n      ImmutableMap.Builder<String, PCollection<?>> indexToPCollection = ImmutableMap.builder();\n      int i = 0;\n      for (PCollection<?> pc : listOutput.getAll()) {\n        indexToPCollection.put(Integer.toString(i), pc);\n        i++;\n      }\n      return indexToPCollection.build();\n    } else if (output != null) {\n      // This is needed to support custom output types.\n      Map<TupleTag<?>, PValue> values = output.expand();\n      Map<String, PCollection<?>> returnMap = new HashMap<>();\n      for (Map.Entry<TupleTag<?>, PValue> entry : values.entrySet()) {\n        if (!(entry.getValue() instanceof PCollection)) {\n          throw new UnsupportedOperationException(\n              \"Unable to parse the output type \"\n                  + output.getClass()\n                  + \" due to key \"\n                  + entry.getKey()\n                  + \" not mapping to a PCollection\");\n        }\n        returnMap.put(entry.getKey().getId(), (PCollection<?>) entry.getValue());\n      }\n      return returnMap;\n    } else {\n      throw new UnsupportedOperationException(\"Unknown output type: \" + output.getClass());\n    }\n  }\n\n  default Map<String, PCollection<?>> apply(\n      Pipeline p, String name, RunnerApi.FunctionSpec spec, Map<String, PCollection<?>> inputs) {\n    return extractOutputs(\n        Pipeline.applyTransform(name, createInput(p, inputs), getTransform(spec, p.getOptions())));","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/expansion-service/src/main/java/org/apache/beam/sdk/expansion/service/TransformProvider.java#L92-L128","documentation":"extractOutputs expects a transform's POutput to expand into values that are all PCollections. When some TupleTag maps to a non-PCollection PValue, the provider cannot expose it as a named output and throws, naming the output type and offending key.","triggerScenarios":"Using a custom POutput/transform whose expand() returns non-PCollection PValues (e.g. PCollectionViews or side artifacts) as expansion-service transform output.","commonSituations":"Custom transforms returning views or side inputs as outputs; wrappers not designed for cross-language expansion.","solutions":["Change the transform so its POutput contains only PCollections per TupleTag.","Expose auxiliary values as additional PCollections rather than raw PValues.","Wrap the transform to extract only its PCollection outputs before registering.","Register an expansion-compatible variant of the transform."],"exampleFix":"// before\noutputMap.put(tag, (PValue) pCollectionView);\n// after\noutputMap.put(tag, resultingPCollection);","handlingStrategy":"type-guard","validationCode":"Map<TupleTag<?>, PValue> vals = output.expand();\nvals.forEach((tag, v) -> { if (!(v instanceof PCollection)) throw new IllegalArgumentException(\"Output \" + tag + \" is not a PCollection\"); });","typeGuard":"boolean hasOnlyPCollections(POutput out) { return out.expand().values().stream().allMatch(v -> v instanceof PCollection); }","tryCatchPattern":"try { Map<String, PCollection<?>> outs = provider.extractOutputs(output); } catch (UnsupportedOperationException e) { log.error(\"Unsupported output: {}\", e.getMessage()); throw new TransformContractException(e); }","preventionTips":["Design expansion-facing transforms with PCollection-only outputs","Test custom transforms through the expansion service before registering","Avoid exposing PCollectionView as output","Review POutput.expand() implementations for non-PCollection values"],"tags":["beam","expansion","pcollection"],"backgroundTag":"type-mismatch","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"}