{"record":{"id":"dfe84a98d8bd7609","repo":"apache/pulsar","slug":"function-takes-two-arguments-but-the-first-is-not","errorCode":null,"errorMessage":"function takes two arguments, but the first is not Context. got %s","messagePattern":"function takes two arguments, but the first is not Context\\. got (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pulsar-function-go/pf/function.go","lineNumber":71,"sourceCode":"\treturn output, nil\n}\n\nfunc errorHandler(e error) pulsarFunction {\n\treturn func(ctx context.Context, input []byte) ([]byte, error) {\n\t\treturn nil, e\n\t}\n}\n\nfunc validateArguments(handler reflect.Type) (bool, error) {\n\thandlerTakesContext := false\n\tif handler.NumIn() > 2 {\n\t\treturn false, fmt.Errorf(\"functions may not take more than two arguments, but function takes %d\", handler.NumIn())\n\t} else if handler.NumIn() > 0 {\n\t\tcontextType := reflect.TypeOf((*context.Context)(nil)).Elem()\n\t\targumentType := handler.In(0)\n\t\thandlerTakesContext = argumentType.Implements(contextType)\n\t\tif handler.NumIn() > 1 && !handlerTakesContext {\n\t\t\treturn false, fmt.Errorf(\"function takes two arguments, but the first is not Context. got %s\", argumentType.Kind())\n\t\t}\n\t}\n\n\treturn handlerTakesContext, nil\n}\n\nfunc validateReturns(handler reflect.Type) error {\n\terrorType := reflect.TypeOf((*error)(nil)).Elem()\n\n\tswitch {\n\tcase handler.NumOut() > 2:\n\t\treturn fmt.Errorf(\"function may not return more than two values\")\n\tcase handler.NumOut() > 1:\n\t\tif !handler.Out(1).Implements(errorType) {\n\t\t\treturn fmt.Errorf(\"function returns two values, but the second does not implement error\")\n\t\t}\n\tcase handler.NumOut() == 1:\n\t\tif !handler.Out(0).Implements(errorType) {","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-function-go/pf/function.go#L53-L89","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Change the first parameter to ctx context.Context (and put the payload second).","If no context is needed, use a single-parameter handler func(msg T).","Ensure any custom context type embeds/implements context.Context.","Adapt legacy signatures with a closure: func(ctx context.Context, msg []byte) { return legacy(msg, ...) }."],"exampleFix":"// before\nfunc handle(msg []byte, ctx *MyContext) ([]byte, error) { ... }\n// after\nfunc handle(ctx context.Context, msg []byte) ([]byte, error) { ... }","handlingStrategy":"validation","validationCode":"func takesContextFirst(handler interface{}) bool {\n    t := reflect.TypeOf(handler)\n    if t == nil || t.Kind() != reflect.Func || t.NumIn() == 0 {\n        return false\n    }\n    ctxType := reflect.TypeOf((*context.Context)(nil)).Elem()\n    if t.NumIn() == 1 {\n        return true // single-arg handlers are fine regardless\n    }\n    return t.In(0).Implements(ctxType)\n}","typeGuard":"func firstArgIsContext(handler interface{}) bool {\n    t := reflect.TypeOf(handler)\n    ctxType := reflect.TypeOf((*context.Context)(nil)).Elem()\n    return t.Kind() == reflect.Func && t.NumIn() > 1 && t.In(0).Implements(ctxType)\n}","tryCatchPattern":"f, err := pf.NewGoFunction(ctx, pf.GoFunction{\n    Handler: myHandler,\n})\nif err != nil {\n    if strings.Contains(err.Error(), \"first is not Context\") {\n        log.Fatalf(\"handler signature invalid: first parameter must be context.Context: %v\", err)\n    }\n    log.Fatalf(\"function registration failed: %v\", err)\n}","preventionTips":["Always write two-argument handlers as (ctx context.Context, msg T) — ctx first, payload second.","Use a single-argument handler if you don't need the context.","Never swap parameter order; the check is positional.","Add a unit test that constructs the function before deploying."],"tags":["go","pulsar-functions","reflection","context"],"backgroundTag":"invalid-function-signature","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}