apache/pulsar · error
function may not return more than two values
Error message
function may not return more than two values
What it means
validateReturns restricts handler return arity: a Go function may return either nothing, one error, or (result, error). A handler whose reflect type has NumOut() > 2 cannot be invoked correctly by the framework, so newFunction fails with this error.
Source
Thrown at pulsar-function-go/pf/function.go:83
return false, fmt.Errorf("functions may not take more than two arguments, but function takes %d", handler.NumIn())
} else if handler.NumIn() > 0 {
contextType := reflect.TypeOf((*context.Context)(nil)).Elem()
argumentType := handler.In(0)
handlerTakesContext = argumentType.Implements(contextType)
if handler.NumIn() > 1 && !handlerTakesContext {
return false, fmt.Errorf("function takes two arguments, but the first is not Context. got %s", argumentType.Kind())
}
}
return handlerTakesContext, nil
}
func validateReturns(handler reflect.Type) error {
errorType := reflect.TypeOf((*error)(nil)).Elem()
switch {
case handler.NumOut() > 2:
return fmt.Errorf("function may not return more than two values")
case handler.NumOut() > 1:
if !handler.Out(1).Implements(errorType) {
return fmt.Errorf("function returns two values, but the second does not implement error")
}
case handler.NumOut() == 1:
if !handler.Out(0).Implements(errorType) {
return fmt.Errorf("function returns a single value, but it does not implement error")
}
}
return nil
}
func newFunction(inputFunc interface{}) function {
if inputFunc == nil {
return errorHandler(fmt.Errorf("function is nil"))
}
handler := reflect.ValueOf(inputFunc)View on GitHub (pinned to 820761864e)
Solutions
- Return at most two values: a single output of type T plus an error.
- Pack extra outputs into the single result (struct, map, or serialized payload).
- Log diagnostics instead of returning them; publish additional data to other topics via the output topic.
- Adapt with a wrapper that drops/merges extra return values into one.
Example fix
// before
func handle(ctx context.Context, msg []byte) ([]byte, []byte, error) { ... }
// after
type result struct{ Out []byte; Extra []byte }
func handle(ctx context.Context, msg []byte) (result, error) { ... } Defensive patterns
Strategy: validation
Validate before calling
func validReturnArity(handler interface{}) bool {
t := reflect.TypeOf(handler)
return t != nil && t.Kind() == reflect.Func && t.NumOut() <= 2
} Type guard
func returnsAtMostTwo(handler interface{}) bool {
t := reflect.TypeOf(handler)
return t.Kind() == reflect.Func && t.NumOut() <= 2
} Try / catch
f, err := pf.NewGoFunction(ctx, pf.GoFunction{
Handler: myHandler,
})
if err != nil {
log.Fatalf("invalid handler returns: %v", err)
} Prevention
- Follow the (T, error) convention — one output plus error, nothing more.
- Aggregate multiple outputs into a single struct or serialized payload.
- Publish side outputs to separate topics instead of returning them.
- Review signatures after refactors that add return values.
When it happens
Trigger: Registering a handler returning three or more values, e.g. func(ctx context.Context, msg []byte) ([]byte, []byte, error), or returning multiple results plus error.
Common situations: Trying to return both an output message and extra diagnostics; porting handlers that return (value, metadata, error); misunderstanding that only a single output plus error is supported.
Related errors
- functions may not take more than two arguments, but function
- function takes two arguments, but the first is not Context.
- function returns two values, but the second does not impleme
- function returns a single value, but it does not implement e
- The specified go executable binary does not exist
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/e011af41467fa30f.
Report an issue: GitHub.