apache/beam · error

Invalid signature for FinishBundle

Error message

Invalid signature for FinishBundle

What it means

This panic is the inner default of buildFinishBundleWrapper for the 0-input case: the FinishBundle output count was neither 0 nor 1. Beam only permits FinishBundle to return nothing or a single error, so any other number of return values is an invalid signature and registration aborts.

Source

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

	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]()
			} else if _, ok := doFn.(finishBundle1x0[typex.PaneInfo]); ok {
				return registerFinishBundle1x0FuncAndMakeStructWrapper[typex.PaneInfo]()
			} else if _, ok := doFn.(finishBundle1x0[[]typex.Window]); ok {
				return registerFinishBundle1x0FuncAndMakeStructWrapper[[]typex.Window]()
			} else if _, ok := doFn.(finishBundle1x0[typex.EventTime]); ok {
				return registerFinishBundle1x0FuncAndMakeStructWrapper[typex.EventTime]()
			} else if _, ok := doFn.(finishBundle1x0[typex.BundleFinalization]); ok {
				return registerFinishBundle1x0FuncAndMakeStructWrapper[typex.BundleFinalization]()
			} else {

View on GitHub (pinned to 12126d8942)

Solutions

  1. Change FinishBundle to return nothing or exactly one error value.
  2. Log diagnostics instead of returning extra values from FinishBundle.
  3. Move metrics/extra outputs to ProcessElement or bundle finalization callbacks (BundleFinalization).
  4. Re-run registration after fixing; the panic occurs at pipeline construction time, not runtime execution.

Example fix

// before
func (fn *myFn) FinishBundle() (int, error) { ... }
// after
func (fn *myFn) FinishBundle() error { ... }
Defensive patterns

Strategy: validation

Validate before calling

t := reflect.TypeOf(&myFn{}).Elem().MethodByName("FinishBundle").Type
if t.NumOut() > 1 { panic("FinishBundle may return at most one error") }

Type guard

func atMostOneReturn(t reflect.Type) bool { return t.NumOut() <= 1 }

Try / catch

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

Prevention

When it happens

Trigger: A FinishBundle method with no inputs returning two or more values (e.g. (int, error)) or three values, then the DoFn is registered via register.DoFn/used in a pipeline.

Common situations: Copying ProcessElement's multi-return style onto FinishBundle; adding a debug return value to FinishBundle during development and forgetting to remove it.

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/8262a8f16b1805a3. Report an issue: GitHub.