apache/beam · error · java.lang.UnsupportedOperationException

Cannot create from non-Java

Error message

Cannot create %s from non-Java %s: %s

What it means

When translating a RunnerApi StateSpec back into a Java StateSpec, a COMBINING spec must carry a combine FunctionSpec with the Java serialized combine fn URN (beam:combine_fn:java_serialized:v1). Any other URN means the combine function is not a Java-serializable one, so Beam cannot reconstruct a Java CombineFn and throws this UnsupportedOperationException.

Solutions

  1. Ensure the state spec's combine fn is defined in Java and serialized via CombineTranslation's Java serialized URN
  2. Avoid Java-specific state/combine translation for portable graphs; use runner-side portable handling instead of ParDoTranslation
  3. Regenerate the pipeline proto so Java-side DoFns are encoded with the serialized Java combine fn

Example fix

// before
FunctionSpec combineFnSpec = FunctionSpec.newBuilder().setUrn("beam:combine_fn:custom:v1").build();
// after
FunctionSpec combineFnSpec = CombineTranslation.combineFnToSpec(Sum.ofIntegers()); // uses JAVA_SERIALIZED_COMBINE_FN_URN
Defensive patterns

Strategy: validation

Validate before calling

FunctionSpec spec = stateSpec.getCombiningSpec().getCombineFn();
if (!CombineTranslation.JAVA_SERIALIZED_COMBINE_FN_URN.equals(spec.getUrn())) throw new IllegalArgumentException("non-Java combine fn: " + spec.getUrn());

Type guard

boolean isJavaSerializedCombineFn(FunctionSpec s) { return s != null && CombineTranslation.JAVA_SERIALIZED_COMBINE_FN_URN.equals(s.getUrn()); }

Try / catch

try { StateSpec<?> s = ParDoTranslation.stateSpecFromProto(stateSpec, components); } catch (UnsupportedOperationException e) { /* fall back to portable translation path */ }

Prevention

When it happens

Trigger: Calling ParDoTranslation.stateSpecFromProto (via graph translation) on a state spec whose combining spec references a combine fn URN other than JAVA_SERIALIZED_COMBINE_FN_URN — e.g. a portably-encoded/custom combine fn produced by another SDK or expansion service.

Common situations: Cross-language pipelines where a Python/Go transform defines stateful combining; using an expansion service that emits portable combine URNs; mixing Beam versions where combine fn encoding differs.

Related errors


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

Appendix: source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/util/construction/ParDoTranslation.java:680

                .build();
          }
        });
  }

  @VisibleForTesting
  static StateSpec<?> fromProto(RunnerApi.StateSpec stateSpec, RehydratedComponents components)
      throws IOException {
    switch (stateSpec.getSpecCase()) {
      case READ_MODIFY_WRITE_SPEC:
        return StateSpecs.value(
            components.getCoder(stateSpec.getReadModifyWriteSpec().getCoderId()));
      case BAG_SPEC:
        return StateSpecs.bag(components.getCoder(stateSpec.getBagSpec().getElementCoderId()));
      case COMBINING_SPEC:
        FunctionSpec combineFnSpec = stateSpec.getCombiningSpec().getCombineFn();

        if (!combineFnSpec.getUrn().equals(CombineTranslation.JAVA_SERIALIZED_COMBINE_FN_URN)) {
          throw new UnsupportedOperationException(
              String.format(
                  "Cannot create %s from non-Java %s: %s",
                  StateSpec.class.getSimpleName(),
                  Combine.CombineFn.class.getSimpleName(),
                  combineFnSpec.getUrn()));
        }

        Combine.CombineFn<?, ?, ?> combineFn =
            (Combine.CombineFn<?, ?, ?>)
                SerializableUtils.deserializeFromByteArray(
                    combineFnSpec.getPayload().toByteArray(),
                    Combine.CombineFn.class.getSimpleName());

        // Rawtype coder cast because it is required to be a valid accumulator coder
        // for the CombineFn, by construction
        return StateSpecs.combining(
            (Coder) components.getCoder(stateSpec.getCombiningSpec().getAccumulatorCoderId()),
            combineFn);

View on GitHub (pinned to 12126d8942)