apache/beam · error · UnsupportedOperationException
Unable to parse the output type
Error message
Unable to parse the output type ${output.getClass()} due to key ${entry.getKey()} not mapping to a PCollection What it means
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.
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.
Example fix
// before outputMap.put(tag, (PValue) pCollectionView); // after outputMap.put(tag, resultingPCollection);
Defensive patterns
Strategy: type-guard
Validate before calling
Map<TupleTag<?>, PValue> vals = output.expand();
vals.forEach((tag, v) -> { if (!(v instanceof PCollection)) throw new IllegalArgumentException("Output " + tag + " is not a PCollection"); }); Type guard
boolean hasOnlyPCollections(POutput out) { return out.expand().values().stream().allMatch(v -> v instanceof PCollection); } Try / catch
try { Map<String, PCollection<?>> outs = provider.extractOutputs(output); } catch (UnsupportedOperationException e) { log.error("Unsupported output: {}", e.getMessage()); throw new TransformContractException(e); } Prevention
- 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
When it happens
Trigger: Using a custom POutput/transform whose expand() returns non-PCollection PValues (e.g. PCollectionViews or side artifacts) as expansion-service transform output.
Common situations: Custom transforms returning views or side inputs as outputs; wrappers not designed for cross-language expansion.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Unknown output type
- Unable to perform expansion for transform
- A dataSourceConfiguration or dataSourceProviderFn has…
- A list of URNs for overriding transforms was provided but…
- A cannot be expanded
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/b1eeb0decf889990.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/expansion-service/src/main/java/org/apache/beam/sdk/expansion/service/TransformProvider.java:110
return ((PCollectionTuple) output)
.getAll().entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey().getId(), Map.Entry::getValue));
} else if (output instanceof PCollectionList<?>) {
PCollectionList<?> listOutput = (PCollectionList<?>) output;
ImmutableMap.Builder<String, PCollection<?>> indexToPCollection = ImmutableMap.builder();
int i = 0;
for (PCollection<?> pc : listOutput.getAll()) {
indexToPCollection.put(Integer.toString(i), pc);
i++;
}
return indexToPCollection.build();
} else if (output != null) {
// This is needed to support custom output types.
Map<TupleTag<?>, PValue> values = output.expand();
Map<String, PCollection<?>> returnMap = new HashMap<>();
for (Map.Entry<TupleTag<?>, PValue> entry : values.entrySet()) {
if (!(entry.getValue() instanceof PCollection)) {
throw new UnsupportedOperationException(
"Unable to parse the output type "
+ output.getClass()
+ " due to key "
+ entry.getKey()
+ " not mapping to a PCollection");
}
returnMap.put(entry.getKey().getId(), (PCollection<?>) entry.getValue());
}
return returnMap;
} else {
throw new UnsupportedOperationException("Unknown output type: " + output.getClass());
}
}
default Map<String, PCollection<?>> apply(
Pipeline p, String name, RunnerApi.FunctionSpec spec, Map<String, PCollection<?>> inputs) {
return extractOutputs(
Pipeline.applyTransform(name, createInput(p, inputs), getTransform(spec, p.getOptions())));View on GitHub (pinned to 12126d8942)