apache/beam · error · UnsupportedOperationException

Unknown output type

Error message

Unknown output type: ${output.getClass()}

What it means

extractOutputs expands a custom PTransform output's expand() map and hit an entry whose value is not a PCollection (the unsupported branch for arbitrary PValue outputs). The output object (and its non-PCollection expand value under the reported key) is the input at fault: the expansion service can only wire PCollection outputs back into its response.

Solutions

  1. Ensure the transform always returns a non-null PCollection or POutput.
  2. Check the implementation for early-return/null paths on empty input.
  3. Wrap the transform to produce a standard PCollection output.
  4. Inspect output.getClass() in the message and handle that type upstream.

Example fix

// before
return condition ? transform.expand(input) : null;
// after
PCollection<T> result = transform.expand(input);
return requireNonNull(result, "transform output must not be null");
Defensive patterns

Strategy: validation

Validate before calling

if (output == null) throw new IllegalStateException("Transform produced no output");
if (!(output instanceof PCollection) && !(output instanceof POutput)) throw new IllegalStateException("Unsupported output type: " + output.getClass());

Type guard

boolean hasExtractableOutput(Object out) { return out instanceof PCollection || out instanceof POutput; }

Try / catch

try { Map<String, PCollection<?>> outs = provider.extractOutputs(output); } catch (UnsupportedOperationException e) { log.error("No extractable output: {}", e.getMessage()); throw new TransformContractException(e); }

Prevention

When it happens

Trigger: A transform's apply/expand returns null output; or returns a type not covered by the PCollection/POutput branches in extractOutputs.

Common situations: Custom transforms returning null on failure; third-party PTransform wrappers with nonstandard output types.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/89171ca8177a2642. Report an issue: GitHub.

Appendix: source

Thrown at sdks/java/expansion-service/src/main/java/org/apache/beam/sdk/expansion/service/TransformProvider.java:121

      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())));
  }

  default String getTransformUniqueID(RunnerApi.FunctionSpec spec) {
    if (BeamUrns.getUrn(ExternalTransforms.ExpansionMethods.Enum.SCHEMA_TRANSFORM)
        .equals(spec.getUrn())) {
      ExternalTransforms.SchemaTransformPayload payload;
      try {
        payload = ExternalTransforms.SchemaTransformPayload.parseFrom(spec.getPayload());
        if (PTransformTranslation.MANAGED_TRANSFORM_URN.equals(payload.getIdentifier())) {
          try {
            // ManagedSchemaTransform includes a schema field transform_identifier that includes the

View on GitHub (pinned to 12126d8942)