apache/beam · critical
Failed to optimize CreateAccumulator for combiner %v. Failed
Error message
Failed to optimize CreateAccumulator for combiner %v. Failed to infer types
What it means
Raised by register.Combiner1/2/3 when the combiner value exposes a CreateAccumulator method (found via reflect.MethodByName) but the generated type assertions — createAccumulator0x2[T0] as func() (T0, error) and createAccumulator0x1[T0] as func() T0 — both failed. Beam could not build the optimized creation wrapper for the declared accumulator type T0, so it panics rather than silently using a slow path. Note the guard: it only fires when the method exists but isn't type-inferable.
Source
Thrown at sdks/go/pkg/beam/register/register.tmpl:363
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)
return &caller0x1[T0]{fn: f}
}
reflectx.RegisterFunc(reflect.TypeOf((*func() T0)(nil)).Elem(), caller)
createAccumulatorWrapper = func(fn any) reflectx.Func {
return reflectx.MakeFunc(func() T0 {
return fn.(createAccumulator0x1[T0]).CreateAccumulator()
})
}
}
if m := accumVal.MethodByName("CreateAccumulator"); m.IsValid() && createAccumulatorWrapper == nil {
panic(fmt.Sprintf("Failed to optimize CreateAccumulator for combiner %v. Failed to infer types", accum))
}
var addInputWrapper func(fn any) reflectx.Func
if _, ok := accum.(addInput2x2[T0, T0]); ok {
caller := func(fn any) reflectx.Func {
f := fn.(func(T0, T0) (T0, error))
return &caller2x2[T0, T0, T0, error]{fn: f}
}
reflectx.RegisterFunc(reflect.TypeOf((*func(T0, T0) (T0, error))(nil)).Elem(), caller)
addInputWrapper = func(fn any) reflectx.Func {
return reflectx.MakeFunc(func(a0 T0, a1 T0) (T0, error) {
return fn.(addInput2x2[T0, T0]).AddInput(a0, a1)
})
}
} else if _, ok := accum.(addInput2x1[T0, T0]); ok {
caller := func(fn any) reflectx.Func {
f := fn.(func(T0, T0) T0)View on GitHub (pinned to 12126d8942)
Solutions
- Make CreateAccumulator exactly func() T0 or func() (T0, error) where T0 is the accumulator type argument you passed to Combiner1/2/3.
- Fix the type parameter order: register.Combiner2[AccType, InputType] — accumulator type goes first.
- Remove parameters from CreateAccumulator; move initialization/seed data into struct fields set at construction.
- Register with a pointer (&MyCombiner{}) if methods use pointer receivers, and match named types exactly in the generic argument.
- If the signature can't conform, use the non-optimized registration path instead of Combiner1/2/3.
Example fix
// before: CreateAccumulator returns wrong type vs type param
type CountFn struct{}
func (fn *CountFn) CreateAccumulator() int { return 0 }
register.Combiner1[Count](...) // Count is `type Count int`
// after: align types
type CountFn struct{}
func (fn *CountFn) CreateAccumulator() Count { return Count(0) }
register.Combiner1[Count](&CountFn{}) Defensive patterns
Strategy: type-guard
Validate before calling
// Verify CreateAccumulator shape before CombinerN registration:
func createIsOptimizable[T any](accum any) bool {
_, ok1 := accum.(interface{ CreateAccumulator() (T, error) })
_, ok2 := accum.(interface{ CreateAccumulator() T })
return ok1 || ok2
} Type guard
func isCreateAccumulator0x1[T any](accum any) bool {
_, ok := accum.(interface {
CreateAccumulator() T
})
return ok
} Try / catch
func registerCombinerSafe[T any](accum any) {
defer func() {
if r := recover(); r != nil {
log.Fatalf("CreateAccumulator on %T doesn't match func() T or func() (T, error) for T=%T: %v", accum, *new(T), r)
}
}()
register.Combiner1[T](accum)
} Prevention
- Define CreateAccumulator as func() T or func() (T, error) with no parameters and T equal to the accumulator type argument.
- Do initialization via struct fields and a constructor, not CreateAccumulator parameters.
- Match named types exactly: if the accumulator is type Count int, the generic argument must be Count.
- Ensure receiver kind (pointer vs value) matches how you register the combiner.
- Cover every combiner with a registration unit test to catch drift after refactors.
When it happens
Trigger: register.CombinerN[T](&MyCombiner{}) where MyCombiner.CreateAccumulator returns something other than T0 or (T0, error) — e.g. returns a different type than the supplied type parameter, takes parameters (CreateAccumulator(seed T)), returns multiple non-error values, or the accumulator type argument simply doesn't match the method's return type.
Common situations: Wrong generic argument order in Combiner2/Combiner3 (accumulator must be first); CreateAccumulator initialized with config/seed parameters; combining named types vs the primitive type argument (type int vs type Count int); pointer vs value receiver making the interface assertion fail.
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 MergeAccumulators 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/b492a495561cbabe.
Report an issue: GitHub.