apache/beam · error

Failed to optimize MergeAccumulators for combiner %v. Failed

Error message

Failed to optimize MergeAccumulators for combiner %v. Failed to infer types

What it means

During combiner registration, register.go tries to optimize MergeAccumulators by type-asserting the accumulator against generated mergeAccumulatorsNxM shapes. If none match (mergeAccumulatorsWrapper stays nil), it panics because the combiner's accumulator merge signature cannot be inferred and no optimized wrapper can be built.

Source

Thrown at sdks/go/pkg/beam/register/register.go:7894

				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. Implement MergeAccumulators with the canonical signature: MergeAccumulators(a, b A) (A, error) or (a, b A) A, matching the accumulators type used in CreateAccumulator/AddInput
  2. Ensure the combiner is registered with register.Combiner/register.DoFn generics so T0 binds to the accumulator type
  3. Compare your merge method against the mergeAccumulatorsNxM assertions above line 7894 in register.go
  4. Check for Beam version drift between combiner helper signatures

Example fix

// before
func (fn *avgFn) MergeAccumulators(a, b AvgAccum) (AvgAccum, bool) { ... }
// after
func (fn *avgFn) MergeAccumulators(a, b AvgAccum) (AvgAccum, error) { ... }
Defensive patterns

Strategy: validation

Validate before calling

var _ interface { MergeAccumulators(a, b MyAccum) (MyAccum, error) } = (*myCombiner)(nil)

Type guard

func isMergeable2x1[T any](c any) bool {
	_, ok := c.(interface {
		MergeAccumulators(a, b T) (T, error)
	})
	return ok
}

Try / catch

defer func() { if r := recover(); r != nil { err = fmt.Errorf("combiner registration failed: %v", r) } }()

Prevention

When it happens

Trigger: Registering a combiner (via beam.CombineWithContext/register combinators) whose accumulator type does not implement any enumerated mergeAccumulatorsNxM interface — e.g. MergeAccumulators with an unexpected parameter/return combination or a custom accumulator type not tied to the combiner's generic T0.

Common situations: Custom combiners with non-standard MergeAccumulators signatures (extra parameters, non-pair returns), generic combiners instantiated with types that never satisfy mergeAccumulators2x1[T0], or copying combiner code across Beam versions where the enumerated shapes changed.

Related errors


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