apache/beam · critical
Failed to optimize MergeAccumulators for combiner %v. Failed
Error message
Failed to optimize MergeAccumulators for combiner %v. Failed to infer types
What it means
Raised by register.Combiner1/2/3 in Apache Beam Go when the passed CombineFn has a MergeAccumulators method, but none of the generated generic type assertions (mergeAccumulators2x2[T0] returning (T0, error) or mergeAccumulators2x1[T0] returning T0) match it. The framework can't build the optimized (reflection-free) merge wrapper for the given type parameter T, so it panics. This optimization path requires the merge method to operate on the declared accumulator type exactly.
Source
Thrown at sdks/go/pkg/beam/register/register.tmpl:333
return fn.(mergeAccumulators2x2[T0]).MergeAccumulators(a0, a1)
})
}
} else if _, ok := accum.(mergeAccumulators2x1[T0]); ok {
caller := func(fn any) reflectx.Func {
f := fn.(func(T0, T0) T0)
return &caller2x1[T0, T0, T0]{fn: f}
}
reflectx.RegisterFunc(reflect.TypeOf((*func(T0, T0) T0)(nil)).Elem(), caller)
mergeAccumulatorsWrapper = func(fn any) reflectx.Func {
return reflectx.MakeFunc(func(a0 T0, a1 T0) T0 {
return fn.(mergeAccumulators2x1[T0]).MergeAccumulators(a0, a1)
})
}
}
if mergeAccumulatorsWrapper == nil {
panic(fmt.Sprintf("Failed to optimize MergeAccumulators for combiner %v. Failed to infer types", accum))
}
var createAccumulatorWrapper func(fn any) reflectx.Func
if _, ok := accum.(createAccumulator0x2[T0]); ok {
caller := func(fn any) reflectx.Func {
f := fn.(func() (T0, error))
return &caller0x2[T0, error]{fn: f}
}
reflectx.RegisterFunc(reflect.TypeOf((*func() (T0, error))(nil)).Elem(), caller)
createAccumulatorWrapper = func(fn any) reflectx.Func {
return reflectx.MakeFunc(func() (T0, error) {
return fn.(createAccumulator0x2[T0]).CreateAccumulator()
})
}
} else if _, ok := accum.(createAccumulator0x1[T0]); ok {
caller := func(fn any) reflectx.Func {
f := fn.(func() T0)View on GitHub (pinned to 12126d8942)
Solutions
- Make MergeAccumulators exactly func(a, b T) T or func(a, b T) (T, error) where T is the type argument passed to Combiner1/2/3.
- Pass the correct type parameters: accumulator type first for Combiner2/Combiner3 (register.Combiner2[AccT, InT]).
- Register the combiner as the same value/receiver kind its methods are defined on (usually &MyCombiner{}).
- If MergeAccumulators legitimately needs a different shape, fall back to the non-optimized registration (register.Combiner without generics / older API).
- Double-check named types vs aliases: ensure the accumulator field/method types are identical to T, not a distinct named type.
Example fix
// before: accumulator type doesn't match type parameter
type AvgCombiner struct{}
func (fn *AvgCombiner) MergeAccumulators(a, b float64) float64 { return a + b }
register.Combiner1[int](&AvgCombiner{})
// after: match types
register.Combiner1[float64](&AvgCombiner{}) // MergeAccumulators is func(float64, float64) float64 Defensive patterns
Strategy: type-guard
Validate before calling
// Verify the combiner's MergeAccumulators matches the generic argument before calling CombinerN:
func mergeIsOptimizable[T any](accum any) bool {
_, ok1 := accum.(interface{ MergeAccumulators(T, T) (T, error) })
_, ok2 := accum.(interface{ MergeAccumulators(T, T) T })
return ok1 || ok2
}
// usage: if !mergeIsOptimizable[float64](c) { fall back to non-optimized registration } Type guard
func isMergeAccumulators2x1[T any](accum any) bool {
_, ok := accum.(interface {
MergeAccumulators(T, T) T
})
return ok
} Try / catch
func registerCombiner[T any](accum any) {
defer func() {
if r := recover(); r != nil {
log.Fatalf("combiner %T not registrable: check MergeAccumulators matches func(T,T)(T) or func(T,T)(T,error) for T=%T: %v", accum, *new(T), r)
}
}()
register.Combiner1[T](accum)
} Prevention
- Keep MergeAccumulators as func(a, b T) T or func(a, b T) (T, error) with T equal to the generic argument.
- For Combiner2/3, always list the accumulator type first in the type parameters.
- Use pointer receivers consistently and register &MyCombiner{}.
- Avoid named types/aliases that differ from the declared generic type argument.
- Unit-test CombinerN registration for every combiner in CI.
When it happens
Trigger: Calling register.Combiner1[T](&MyCombiner{}) (or Combiner2/Combiner3) where MyCombiner.MergeAccumulators does not have signature func(T, T) T or func(T, T) (T, error) for the supplied type argument T — e.g. wrong type parameter supplied, accumulator type differs from T, or the method takes/returns interface or non-generic concrete types that don't unify with T0.
Common situations: Supplying the wrong type parameter (Combiner2[A,B] with mismatched accumulator type); combining on aliases or named types that don't match T; a combiner written before Beam's generics-based registration API being registered via the new optimized path; passing a struct (not pointer) or a value whose methods have value vs pointer receivers mismatching the assertion.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Failed to optimize CreateAccumulator for combiner %v. Failed
- Unable to infer the types of {{$upperName}}
- GroupIntoBatchesWithShardedKey: input PCollection must be KV
- GroupIntoBatchesWithShardedKey: type parameter K (%v) does n
- typex.Bind: %v is not assignable to %v
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/9ab25c9371ec8ba5.
Report an issue: GitHub.