{"record":{"id":"d0d0784095b8a74d","repo":"apache/beam","slug":"unable-to-infer-coder-for-outputt-s-specify-it-explicitly","errorCode":null,"errorMessage":"Unable to infer coder for OutputT (%s). Specify it explicitly using withOutputCoder().","messagePattern":"Unable to infer coder for OutputT \\((.+?)\\)\\. Specify it explicitly using withOutputCoder\\(\\)\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/Watch.java","lineNumber":789,"sourceCode":"\n    @Override\n    public PCollection<KV<InputT, OutputT>> expand(PCollection<InputT> input) {\n      checkNotNull(getPollInterval(), \"pollInterval\");\n      checkNotNull(getTerminationPerInput(), \"terminationPerInput\");\n\n      Coder<OutputT> outputCoder = getOutputCoder();\n      if (outputCoder == null) {\n        // If a coder was not specified explicitly, infer it from the OutputT type parameter\n        // of the PollFn.\n        TypeDescriptor<OutputT> outputT =\n            TypeDescriptors.extractFromTypeParameters(\n                getPollFn().getClosure(),\n                PollFn.class,\n                new TypeVariableExtractor<PollFn<InputT, OutputT>, OutputT>() {});\n        try {\n          outputCoder = input.getPipeline().getCoderRegistry().getCoder(outputT);\n        } catch (CannotProvideCoderException e) {\n          throw new RuntimeException(\n              \"Unable to infer coder for OutputT (\"\n                  + outputT\n                  + \"). Specify it explicitly using withOutputCoder().\");\n        }\n      }\n\n      Coder<KeyT> outputKeyCoder = getOutputKeyCoder();\n      SerializableFunction<OutputT, KeyT> outputKeyFn = getOutputKeyFn();\n      if (getOutputKeyFn() == null) {\n        // This by construction can happen only if OutputT == KeyT\n        outputKeyCoder = (Coder) outputCoder;\n        outputKeyFn = (SerializableFunction) SerializableFunctions.identity();\n      } else {\n        if (outputKeyCoder == null) {\n          // If a coder was not specified explicitly, infer it from the OutputT type parameter\n          // of the output key fn.\n          TypeDescriptor<KeyT> keyT = TypeDescriptors.outputOf(getOutputKeyFn());\n          try {","sourceCodeStart":771,"sourceCodeEnd":807,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/Watch.java#L771-L807","documentation":"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.","triggerScenarios":"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().","commonSituations":"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.","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"],"exampleFix":"// before\nWatch.growthOf(myPollFn); // OutputT uninferrable\n// after\nWatch.growthOf(myPollFn).withOutputCoder(SerializableCoder.of(MyOutput.class));","handlingStrategy":"validation","validationCode":"// Ensure a coder exists for OutputT before applying Watch\ntry {\n  pipeline.getCoderRegistry().getCoder(TypeDescriptor.of(OutputT.class));\n} catch (CannotProvideCoderException e) {\n  growth = growth.withOutputCoder(SerializableCoder.of(OutputT.class));\n}","typeGuard":null,"tryCatchPattern":"try { pc = input.apply(growth); } catch (RuntimeException e) { if (e.getMessage().contains(\"Unable to infer coder\")) { /* reapply with explicit coder */ } }","preventionTips":["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"],"tags":["beam","coder","watch","type-inference"],"backgroundTag":"coder-inference-failed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}