apache/pulsar · error

function takes two arguments, but the first is not Context…

Error message

function takes two arguments, but the first is not Context. got %s

What it means

When a Go function handler declares two input parameters, the framework requires the first to implement context.Context so it can inject the function context. Reflection checks argumentType.Implements(contextType); a non-Context first parameter fails registration with this error, reporting the parameter's reflect.Kind.

Solutions

  1. Change the first parameter to ctx context.Context (and put the payload second).
  2. If no context is needed, use a single-parameter handler func(msg T).
  3. Ensure any custom context type embeds/implements context.Context.
  4. Adapt legacy signatures with a closure: func(ctx context.Context, msg []byte) { return legacy(msg, ...) }.

Example fix

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

Strategy: validation

Validate before calling

func takesContextFirst(handler interface{}) bool {
    t := reflect.TypeOf(handler)
    if t == nil || t.Kind() != reflect.Func || t.NumIn() == 0 {
        return false
    }
    ctxType := reflect.TypeOf((*context.Context)(nil)).Elem()
    if t.NumIn() == 1 {
        return true // single-arg handlers are fine regardless
    }
    return t.In(0).Implements(ctxType)
}

Type guard

func firstArgIsContext(handler interface{}) bool {
    t := reflect.TypeOf(handler)
    ctxType := reflect.TypeOf((*context.Context)(nil)).Elem()
    return t.Kind() == reflect.Func && t.NumIn() > 1 && t.In(0).Implements(ctxType)
}

Try / catch

f, err := pf.NewGoFunction(ctx, pf.GoFunction{
    Handler: myHandler,
})
if err != nil {
    if strings.Contains(err.Error(), "first is not Context") {
        log.Fatalf("handler signature invalid: first parameter must be context.Context: %v", err)
    }
    log.Fatalf("function registration failed: %v", err)
}

Prevention

When it happens

Trigger: A handler like func handle(msg []byte, id int) or func handle(cfg Config, msg []byte) is passed to newFunction; NumIn() == 2 but the first parameter does not implement context.Context, so the signature is rejected.

Common situations: Writing handlers as (payload, metadata) instead of (ctx, payload); parameter order swapped; using a custom context type that does not implement context.Context; porting functions from other runtimes.

Related errors


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

Appendix: source

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

	return output, nil
}

func errorHandler(e error) pulsarFunction {
	return func(ctx context.Context, input []byte) ([]byte, error) {
		return nil, e
	}
}

func validateArguments(handler reflect.Type) (bool, error) {
	handlerTakesContext := false
	if handler.NumIn() > 2 {
		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) {

View on GitHub (pinned to 820761864e)