{"record":{"id":"df7dcbc15755a51d","repo":"apache/beam","slug":"unable-to-infer-combinefn-accumulator-coder","errorCode":null,"errorMessage":"unable to infer CombineFn accumulator coder","messagePattern":"unable to infer CombineFn accumulator coder","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/combine.go","lineNumber":83,"sourceCode":"\t\treturn PCollection{}, addCombinePerKeyCtx(errors.New(\"combine does not support side inputs\"), s)\n\t}\n\n\tcol, err = TryGroupByKey(s, col)\n\tif err != nil {\n\t\treturn PCollection{}, addCombinePerKeyCtx(err, s)\n\t}\n\n\tfn, err := graph.NewCombineFn(combinefn)\n\tif err != nil {\n\t\treturn PCollection{}, addCombinePerKeyCtx(err, s)\n\t}\n\t// This seems like the best place to infer the accumulator coder type, unless\n\t// it's a universal type.\n\t// We can get the fulltype from the return value of the mergeAccumulatorFn\n\t// TODO(lostluck): 2018/05/28 Correctly infer universal type coder if necessary.\n\taccumCoder, err := inferCoder(typex.New(fn.MergeAccumulatorsFn().Ret[0].T))\n\tif err != nil {\n\t\twrapped := errors.Wrap(err, \"unable to infer CombineFn accumulator coder\")\n\t\treturn PCollection{}, addCombinePerKeyCtx(wrapped, s)\n\t}\n\n\tedge, err := graph.NewCombine(s.real, s.scope, fn, col.n, accumCoder, typedefs)\n\tif err != nil {\n\t\treturn PCollection{}, addCombinePerKeyCtx(err, s)\n\t}\n\tret := PCollection{edge.Output[0].To}\n\tret.SetCoder(NewCoder(ret.Type()))\n\treturn ret, nil\n}\n","sourceCodeStart":65,"sourceCodeEnd":95,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/combine.go#L65-L95","documentation":"TryCombinePerKey tries to infer the coder for the CombineFn's accumulator type — the return type of MergeAccumulators — by calling inferCoder. If that inference fails (for example the accumulator type is an interface with no coder registered), the error is wrapped as \"unable to infer CombineFn accumulator coder\" and the combine edge is not created. This happens before any data is processed, at pipeline construction time.","triggerScenarios":"Calling beam.CombinePerKey / combine.TryCombine (or TryCombinePerKey) with a CombineFn whose MergeAccumulators return type is an interface type that does not implement json.Marshaler, or whose accumulator type otherwise has no registered coder.","commonSituations":"Custom CombineFns whose accumulator is map[string]interface{} or a custom interface; combiners written generically over accumulator types; upgrading Beam where accumulator coder inference became stricter.","solutions":["Make the accumulator a concrete exported struct type with JSON-serializable fields.","Implement MarshalJSON/UnmarshalJSON on the accumulator type so the default JSON coder applies.","Supply an explicit accumulator coder: use combine.TryCombinePerKey with coder.NewCustomCoder(...) for the accumulator type (see the accumCoder argument to graph.NewCombine).","Read the wrapped cause to see whether it is error 4805 (interface without coder) or 4806 (invalid coder) and fix accordingly.","Move the failing per-key Combine into a global beam.Combine with an explicit coder if per-key inference remains problematic."],"exampleFix":"// before\nfunc (fn *MyCombine) MergeAccumulators(a, b MyAcc) MyAcc { ... } // MyAcc is an interface\n\n// after\ntype myAcc struct { Sum int } // concrete accumulator\nfunc (fn *MyCombine) MergeAccumulators(a, b myAcc) myAcc { return myAcc{a.Sum + b.Sum} }","handlingStrategy":"validation","validationCode":"accumT := fn.MergeAccumulatorsFn().Ret[0].T\nif accumT.Kind() == reflect.Interface && !accumT.Implements(jsonCoderType) {\n  return fmt.Errorf(\"CombineFn accumulator type %v needs a concrete type or explicit coder\", accumT)\n}","typeGuard":"func hasValidAccumulatorCoder(fn *combine.CombineFn) bool {\n  t := fn.MergeAccumulatorsFn().Ret[0].T\n  return t != nil && (t.Kind() != reflect.Interface || t.Implements(jsonCoderType))\n}","tryCatchPattern":"accumCoder, err := inferCoder(typex.New(fn.MergeAccumulatorsFn().Ret[0].T))\nif err != nil {\n  return PCollection{}, addCombinePerKeyCtx(errors.Wrap(err, \"unable to infer CombineFn accumulator coder\"), s)\n}","preventionTips":["Define CombineFn accumulators as concrete exported structs.","Register an accumulator coder explicitly when using custom accumulator types.","Unit-test MergeAccumulators' return type with inferCoder/beam.NewCoder early.","Keep accumulator fields JSON-serializable."],"tags":["go","beam","combine","coder-inference"],"backgroundTag":"unsupported-operation","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}