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

  1. 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.
  2. Pass the correct type parameters: accumulator type first for Combiner2/Combiner3 (register.Combiner2[AccT, InT]).
  3. Register the combiner as the same value/receiver kind its methods are defined on (usually &MyCombiner{}).
  4. If MergeAccumulators legitimately needs a different shape, fall back to the non-optimized registration (register.Combiner without generics / older API).
  5. 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

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


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/9ab25c9371ec8ba5. Report an issue: GitHub.