apache/beam · error

Unable to infer the types of FinishBundle

Error message

Unable to infer the types of FinishBundle

What it means

In buildFinishBundleWrapper, the finishBundleIn == 0, finishBundleOut == 0 case asserts the DoFn implements finishBundle0x0 (a FinishBundle with no inputs and no outputs). If the assertion fails, the library cannot infer the types for the wrapper and panics. FinishBundle supports only a small set of signatures (optional context/EventTime/BundleFinalization inputs, nothing or error returned).

Source

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

func buildFinishBundleWrapper[I0, I1, I2, I3, I4, I5, I6, I7, I8, I9 any](doFn any) func(any) reflectx.Func {
	finishBundleIn := -1
	finishBundleOut := -1
	finishBundleMethod := reflect.ValueOf(doFn).MethodByName("FinishBundle")
	if !finishBundleMethod.IsValid() {
		return nil
	}
	finishBundleIn = finishBundleMethod.Type().NumIn()
	finishBundleOut = finishBundleMethod.Type().NumOut()
	switch {

	case finishBundleIn == 0:
		switch {
		case finishBundleOut == 0:
			if _, ok := doFn.(finishBundle0x0); ok {
				return registerFinishBundle0x0FuncAndMakeStructWrapper()
			} else {
				panic("Unable to infer the types of FinishBundle")
			}
		case finishBundleOut == 1:
			if _, ok := doFn.(finishBundle0x1[error]); ok {
				return registerFinishBundle0x1FuncAndMakeStructWrapper[error]()
			} else {
				panic("Unable to infer the types of FinishBundle")
			}
		default:
			panic("Invalid signature for FinishBundle")
		}

	case finishBundleIn == 1:
		switch {
		case finishBundleOut == 0:
			if _, ok := doFn.(finishBundle1x0[I9]); ok {
				return registerFinishBundle1x0FuncAndMakeStructWrapper[I9]()
			} else if _, ok := doFn.(finishBundle1x0[context.Context]); ok {
				return registerFinishBundle1x0FuncAndMakeStructWrapper[context.Context]()

View on GitHub (pinned to 12126d8942)

Solutions

  1. Define FinishBundle with a pointer receiver: func (fn *myFn) FinishBundle().
  2. Ensure FinishBundle returns either nothing or exactly one error.
  3. Pass the DoFn pointer (&myFn{}) to register.DoFn so the interface assertion can match.
  4. Rename the method to exactly FinishBundle.

Example fix

// before
func (fn myFn) FinishBundle() bool { ... }
// after
func (fn *myFn) FinishBundle() { ... }
Defensive patterns

Strategy: validation

Validate before calling

st := reflect.TypeOf(&myFn{}).Elem()
if m, ok := st.MethodByName("FinishBundle"); ok {
    if m.Type.NumIn() != 1 || m.Type.NumOut() != 0 { panic("0-input FinishBundle must be func() with no returns") }
}

Type guard

func isBareFinishBundle(fn any) bool { _, ok := fn.(interface{ FinishBundle() }); return ok }

Try / catch

defer func() { if r := recover(); r != nil { err = fmt.Errorf("FinishBundle not registerable: %v", r) } }()

Prevention

When it happens

Trigger: A DoFn whose FinishBundle takes 0 inputs but is not exactly func() — e.g. it returns a non-error value, or the method name/pointer receiver prevents the finishBundle0x0 interface assertion from succeeding.

Common situations: Defining FinishBundle with a value receiver while the assertion is done against the pointer-typed doFn; naming the method Finishbundle; giving FinishBundle an unsupported return type like (bool).

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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