apache/beam · error

Incompatible func type: got func

Error message

Incompatible func type: got func %v with %v inputs and %v outputs, want 3 inputs and 0 outputs

What it means

reflectx.ToFunc3x0 converts a generic Func to a strongly-typed Func3x0 (3 inputs, 0 outputs). It panics when the underlying reflect.Type's NumIn() is not 3 or NumOut() is not 0. The Beam SDK does this to guarantee that reflection-based invocation inside the pipeline can supply exactly the expected arguments and consume no return values, failing fast with the actual type printed in the message.

Solutions

  1. Make the wrapped function take exactly 3 parameters and return nothing (no error return).
  2. If the function must return values or an error, use the appropriate converter such as ToFunc3x1/ToFunc3x2.
  3. Verify the function's signature with reflect.TypeOf(fn).NumIn()/NumOut() before wrapping.
  4. If extra params are unwanted, close over them in the enclosing scope so the func literal itself has exactly 3 declared parameters.

Example fix

// before
f := reflectx.ToFunc3x0(func(key string, val int, emit func(int)) error { return nil }) // returns error, panics
// after
f := reflectx.ToFunc3x0(func(key string, val int, emit func(int)) {
    emit(val)
})
Defensive patterns

Strategy: validation

Validate before calling

t := reflect.TypeOf(fn)
if t.NumIn() != 3 || t.NumOut() != 0 {
    panic(fmt.Sprintf("expected 3-in/0-out func, got %v (%d in, %d out)", t, t.NumIn(), t.NumOut()))
}
f := reflectx.ToFunc3x0(f)

Type guard

func isFunc3x0(fn any) bool {
    t := reflect.TypeOf(fn)
    return t != nil && t.Kind() == reflect.Func && t.NumIn() == 3 && t.NumOut() == 0
}

Try / catch

func safeToFunc3x0(f reflectx.Func) (out reflectx.Func3x0, err error) {
    defer func() { if r := recover(); r != nil { err = fmt.Errorf("ToFunc3x0: %v", r) } }()
    out = reflectx.ToFunc3x0(f)
    return
}

Prevention

When it happens

Trigger: Calling reflectx.ToFunc3x0(f) where f.Type().NumIn() != 3 (e.g. 2 or 4 params) or f.Type().NumOut() != 0 (the function returns 1+ values, such as an error).

Common situations: Wrapping a sink-style function that accidentally returns a value or error, registering a function with an extra context/emitter parameter added during refactoring, or pointing at the wrong converter for a 3-input function that actually returns results (should be ToFunc3x1 or higher).

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/20a523bd68cbef74. Report an issue: GitHub.

Appendix: source

Thrown at sdks/go/pkg/beam/core/util/reflectx/calls.go:680

}

func (c *shimFunc3x0) Type() reflect.Type {
	return c.inner.Type()
}

func (c *shimFunc3x0) Call(args []any) []any {
	return c.inner.Call(args)
}

func (c *shimFunc3x0) Call3x0(arg0, arg1, arg2 any) {
	ret := c.inner.Call([]any{arg0, arg1, arg2})
	_ = ret
	return
}

func ToFunc3x0(c Func) Func3x0 {
	if c.Type().NumIn() != 3 || c.Type().NumOut() != 0 {
		panic(fmt.Sprintf("Incompatible func type: got func %v with %v inputs and %v outputs, want 3 inputs and 0 outputs", c.Type(), c.Type().NumIn(), c.Type().NumOut()))
	}
	if sc, ok := c.(Func3x0); ok {
		return sc
	}
	return &shimFunc3x0{inner: c}
}

func MakeFunc3x0(fn any) Func3x0 {
	return ToFunc3x0(MakeFunc(fn))
}

type Func3x1 interface {
	Func
	Call3x1(any, any, any) any
}

type shimFunc3x1 struct {
	inner Func

View on GitHub (pinned to 12126d8942)