apache/beam · error · IllegalArgumentException

Unknown type of fn class %s

Error message

Unknown type of fn class %s

What it means

FlatMapElements.via(fn) accepts only a few fn shapes: a function/SerializableFunction, or (in the failing expand) a specific class type it knows how to adapt into a DoFn. When the fn object is of any other class, expand throws this IllegalArgumentException.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/FlatMapElements.java:174

                      .getRequirements()
                      .getSideInputs()));
    } else if (fn instanceof ProcessFunction) {
      return input.apply(
          "FlatMap",
          ParDo.of(
              new FlatMapDoFn() {
                @ProcessElement
                public void processElement(
                    @Element InputT element, OutputReceiver<OutputT> receiver) throws Exception {
                  Iterable<OutputT> res =
                      ((ProcessFunction<InputT, Iterable<OutputT>>) fn).apply(element);
                  for (OutputT output : res) {
                    receiver.output(output);
                  }
                }
              }));
    } else {
      throw new IllegalArgumentException(
          String.format("Unknown type of fn class %s", fn.getClass()));
    }
  }

  private abstract class FlatMapDoFn extends DoFn<InputT, OutputT> {

    @Override
    public TypeDescriptor<InputT> getInputTypeDescriptor() {
      return inputType;
    }

    @Override
    public TypeDescriptor<OutputT> getOutputTypeDescriptor() {
      checkState(
          outputType != null,
          "%s output type descriptor was null; "
              + "this probably means that getOutputTypeDescriptor() was called after "
              + "serialization/deserialization, but it is only available prior to "

View on GitHub (pinned to 12126d8942)

Solutions

  1. Pass a lambda or method reference typed as ProcessFunction<InputT, Iterable<OutputT>>
  2. Ensure the generic type parameters of FlatMapElements.via(...) match the fn's input/output types
  3. If using a class, implement SerializableFunction<InputT, Iterable<OutputT>> (or the required interface) directly

Example fix

// before
FlatMapElements.via(new MyWeirdFn());
// after
FlatMapElements.via((ProcessFunction<String, Iterable<Integer>>) s -> Arrays.asList(s.split(" ")))
Defensive patterns

Strategy: type-guard

Validate before calling

// Verify the fn type before passing to FlatMapElements
if (!(fn instanceof ProcessFunction) && !(fn instanceof SerializableFunction)) {
  throw new IllegalArgumentException("fn must be a ProcessFunction/SerializableFunction");
}

Type guard

boolean isValidFlatMapFn(Object fn) {
  return fn instanceof ProcessFunction || fn instanceof SerializableFunction;
}

Try / catch

try { pc.apply(FlatMapElements.into(td).via(fn)); }
catch (IllegalArgumentException e) { log.error("bad fn class", e); }

Prevention

When it happens

Trigger: Calling FlatMapElements.via() with a fn whose runtime class is neither ProcessFunction/SerializableFunction nor one of the supported inner adapter classes (e.g. a class already carrying an output type not matching the expected type parameter).

Common situations: Type-erasure mistakes: passing a lambda assigned to a raw or wrong generic type; reusing a fn class from a different transform; calling via() with an anonymous class of unexpected shape.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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