apache/beam · error

Invalid signature for StartBundle

Error message

Invalid signature for StartBundle

What it means

buildStartBundleWrapper counts the StartBundle method's return values via reflection; any method with 0 inputs but more than 1 output falls into the default branch and panics because StartBundle may only return 0 or 1 values (at most an error). The SDK deliberately rejects multi-return StartBundle signatures at registration time.

Source

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

	startBundleOut = startBundleMethod.Type().NumOut()
	switch {

	case startBundleIn == 0:
		switch {
		case startBundleOut == 0:
			if _, ok := doFn.(startBundle0x0); ok {
				return registerStartBundle0x0FuncAndMakeStructWrapper()
			} else {
				panic("Unable to infer the types of StartBundle")
			}
		case startBundleOut == 1:
			if _, ok := doFn.(startBundle0x1[error]); ok {
				return registerStartBundle0x1FuncAndMakeStructWrapper[error]()
			} else {
				panic("Unable to infer the types of StartBundle")
			}
		default:
			panic("Invalid signature for StartBundle")
		}

	case startBundleIn == 1:
		switch {
		case startBundleOut == 0:
			if _, ok := doFn.(startBundle1x0[I9]); ok {
				return registerStartBundle1x0FuncAndMakeStructWrapper[I9]()
			} else if _, ok := doFn.(startBundle1x0[context.Context]); ok {
				return registerStartBundle1x0FuncAndMakeStructWrapper[context.Context]()
			} else if _, ok := doFn.(startBundle1x0[typex.PaneInfo]); ok {
				return registerStartBundle1x0FuncAndMakeStructWrapper[typex.PaneInfo]()
			} else if _, ok := doFn.(startBundle1x0[[]typex.Window]); ok {
				return registerStartBundle1x0FuncAndMakeStructWrapper[[]typex.Window]()
			} else if _, ok := doFn.(startBundle1x0[typex.EventTime]); ok {
				return registerStartBundle1x0FuncAndMakeStructWrapper[typex.EventTime]()
			} else if _, ok := doFn.(startBundle1x0[typex.BundleFinalization]); ok {
				return registerStartBundle1x0FuncAndMakeStructWrapper[typex.BundleFinalization]()
			} else {

View on GitHub (pinned to 12126d8942)

Solutions

  1. Reduce StartBundle to at most one return value: either no returns or exactly `error`.
  2. Move any non-error outputs into bundle setup done in Setup() or into the DoFn's fields.
  3. Compare against the documented StartBundle signature options in the Beam Go programming guide.

Example fix

// before
func (fn myDoFn) StartBundle() (int, error) { return 0, nil }

// after
func (fn myDoFn) StartBundle() error { return nil }
Defensive patterns

Strategy: validation

Validate before calling

m := reflect.TypeOf(myDoFn{}).MethodByName("StartBundle")
if m.IsValid && m.Type.NumOut() > 1 { panic("StartBundle must return 0 or 1 values") }

Type guard

func validStartBundleArity(t reflect.Type) bool { m, ok := t.MethodByName("StartBundle"); return !ok || m.Type.NumOut() <= 1 }

Try / catch

defer func() {
	if r := recover(); r != nil {
		log.Fatalf("invalid StartBundle signature: %v", r)
	}
}()

Prevention

When it happens

Trigger: Registering a DoFn whose StartBundle has 0 input parameters and 2+ return values, e.g. `func (fn myDoFn) StartBundle() (int, error)`, and passing it to beam.ParDo.

Common situations: Copy-pasting a ProcessElement-style multi-return signature onto StartBundle; accidentally adding a second return value when adding logging/state; code generators emitting ProcessElement-shaped lifecycle methods.

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/81067257c82d1ce4. Report an issue: GitHub.