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
- Call .withOutputCoder(coder) on the Watch.Growth builder with an explicit Coder<OutputT>
- Ensure the PollFn implementation is a concrete named class with a concrete OutputT type parameter
- Register a coder for OutputT with pipeline.getCoderRegistry().registerCoderForType(...)
- 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
- Always call withOutputCoder() for custom output types
- Avoid lambdas/anonymous PollFn implementations when type info matters
- Register custom type coders in the CoderRegistry at pipeline setup
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
- Unable to infer coder for KeyT
- Key coder must be deterministic
- bad coder kind
- bad decoding function
- bad encoding function
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)