apache/beam · error · RuntimeException

Unable to infer coder for OutputT

Error message

Unable to infer coder for OutputT (%s). Specify it explicitly using withOutputCoder().

What it means

Watch.Growth must code the OutputT values produced by the poll function. When no coder was specified via withOutputCoder(), Beam tries to infer one from the OutputT type parameter via the CoderRegistry; if inference fails (CannotProvideCoderException), it throws a RuntimeException telling you to specify the coder explicitly. This happens when OutputT is a generic type variable, erased type, or a type the registry has no registered coder for.

Solutions

  1. Call .withOutputCoder(coder) on the Watch.Growth builder with an explicit Coder<OutputT>
  2. Ensure the PollFn implementation is a concrete named class with a concrete OutputT type parameter
  3. Register a coder for OutputT with pipeline.getCoderRegistry().registerCoderForType(...)
  4. Use a built-in type (String, KV, etc.) for OutputT so the registry can infer a coder

Example fix

// before
Watch.growthOf(myPollFn); // OutputT uninferrable
// after
Watch.growthOf(myPollFn).withOutputCoder(SerializableCoder.of(MyOutput.class));
Defensive patterns

Strategy: validation

Validate before calling

// Ensure a coder exists for OutputT before applying Watch
try {
  pipeline.getCoderRegistry().getCoder(TypeDescriptor.of(OutputT.class));
} catch (CannotProvideCoderException e) {
  growth = growth.withOutputCoder(SerializableCoder.of(OutputT.class));
}

Try / catch

try { pc = input.apply(growth); } catch (RuntimeException e) { if (e.getMessage().contains("Unable to infer coder")) { /* reapply with explicit coder */ } }

Prevention

When it happens

Trigger: Applying Watch.growthOf(pollFn) where PollFn<InputT,OutputT>'s OutputT resolves to a raw/erased or unregistered type (e.g. anonymous/lambda PollFn losing type info, or a custom type with no registered coder) without calling withOutputCoder().

Common situations: Using a lambda or anonymous class for PollFn so TypeVariableExtractor cannot resolve OutputT; custom POJO output types not registered in the CoderRegistry; typing PollFn with Object or a generic parameter.

Related errors


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

Appendix: source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/Watch.java:789

    @Override
    public PCollection<KV<InputT, OutputT>> expand(PCollection<InputT> input) {
      checkNotNull(getPollInterval(), "pollInterval");
      checkNotNull(getTerminationPerInput(), "terminationPerInput");

      Coder<OutputT> outputCoder = getOutputCoder();
      if (outputCoder == null) {
        // If a coder was not specified explicitly, infer it from the OutputT type parameter
        // of the PollFn.
        TypeDescriptor<OutputT> outputT =
            TypeDescriptors.extractFromTypeParameters(
                getPollFn().getClosure(),
                PollFn.class,
                new TypeVariableExtractor<PollFn<InputT, OutputT>, OutputT>() {});
        try {
          outputCoder = input.getPipeline().getCoderRegistry().getCoder(outputT);
        } catch (CannotProvideCoderException e) {
          throw new RuntimeException(
              "Unable to infer coder for OutputT ("
                  + outputT
                  + "). Specify it explicitly using withOutputCoder().");
        }
      }

      Coder<KeyT> outputKeyCoder = getOutputKeyCoder();
      SerializableFunction<OutputT, KeyT> outputKeyFn = getOutputKeyFn();
      if (getOutputKeyFn() == null) {
        // This by construction can happen only if OutputT == KeyT
        outputKeyCoder = (Coder) outputCoder;
        outputKeyFn = (SerializableFunction) SerializableFunctions.identity();
      } else {
        if (outputKeyCoder == null) {
          // If a coder was not specified explicitly, infer it from the OutputT type parameter
          // of the output key fn.
          TypeDescriptor<KeyT> keyT = TypeDescriptors.outputOf(getOutputKeyFn());
          try {

View on GitHub (pinned to 12126d8942)