apache/pulsar · error

function returns a single value, but it does not implement e

Error message

function returns a single value, but it does not implement error

What it means

A single-value handler must return only an error (func(msg T) error), since with one output there is nowhere to put a result. Reflection checks handler.Out(0).Implements(errorType); returning any other single value fails registration in newFunction.

Source

Thrown at pulsar-function-go/pf/function.go:90

		}
	}

	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)
	handlerType := reflect.TypeOf(inputFunc)
	if handlerType.Kind() != reflect.Func {
		return errorHandler(fmt.Errorf("function kind %s is not %s", handlerType.Kind(), reflect.Func))
	}

	takesContext, err := validateArguments(handlerType)
	if err != nil {

View on GitHub (pinned to 820761864e)

Solutions

  1. Return (T, error) instead of just T so the value is recognized as output.
  2. If the function has no meaningful output, return only error: func(msg T) error.
  3. Never return a bare non-error value; the framework treats lone error as a success-with-no-output contract.
  4. Adapt existing logic with a wrapper returning (result, nil).

Example fix

// before
func handle(ctx context.Context, msg []byte) []byte { ... }
// after
func handle(ctx context.Context, msg []byte) ([]byte, error) {
    return transform(msg), nil
}
Defensive patterns

Strategy: validation

Validate before calling

func singleReturnIsError(handler interface{}) bool {
    t := reflect.TypeOf(handler)
    errType := reflect.TypeOf((*error)(nil)).Elem()
    return t.Kind() == reflect.Func && t.NumOut() == 1 && t.Out(0).Implements(errType)
}

Type guard

func isErrOnlyHandler(handler interface{}) bool {
    t := reflect.TypeOf(handler)
    errType := reflect.TypeOf((*error)(nil)).Elem()
    return t.Kind() == reflect.Func && t.NumOut() == 1 && t.Out(0).Implements(errType)
}

Try / catch

f, err := pf.NewGoFunction(ctx, pf.GoFunction{
    Handler: myHandler,
})
if err != nil {
    if strings.Contains(err.Error(), "single value") {
        log.Fatalf("single-return handler must return only error: %v", err)
    }
    log.Fatalf("function registration failed: %v", err)
}

Prevention

When it happens

Trigger: Registering func(msg []byte) []byte or func(ctx context.Context, msg []byte) string — NumOut()==1 but the sole return type does not implement error.

Common situations: Writing map-style handlers that return only the transformed value, assuming return-only-value signatures are supported; forgetting to return an error alongside the result; porting from frameworks that accept bare-value handlers.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/7f07c0f5550e4ba0. Report an issue: GitHub.