{"record":{"id":"49cfa4e7fc48d28c","repo":"apache/pulsar","slug":"functions-may-not-take-more-than-two-arguments-bu","errorCode":null,"errorMessage":"functions may not take more than two arguments, but function takes %d","messagePattern":"functions may not take more than two arguments, but function takes (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pulsar-function-go/pf/function.go","lineNumber":65,"sourceCode":"\toutput, err := function(ctx, input)\n\tif err != nil {\n\t\tlog.Errorf(\"process function error:[%s]\\n\", err.Error())\n\t\treturn nil, err\n\t}\n\n\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\")","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-function-go/pf/function.go#L47-L83","documentation":"validateArguments uses reflection to inspect a Go function supplied as a Pulsar Function handler. Handlers may take at most two inputs: an optional context.Context plus the message payload. A handler with NumIn() > 2 cannot be mapped and newFunction fails with this error.","triggerScenarios":"Registering a handler via pf.NewGoFunction (or the instance path in newFunction) whose signature has three or more input parameters, e.g. func(ctx context.Context, msg []byte, extra string) ([]byte, error).","commonSituations":"Developers coming from other frameworks assume extra parameters (message ID, properties, logger) can be injected; refactoring adds a parameter for convenience; generic helper functions reused as handlers.","solutions":["Reduce the handler to at most two parameters: (ctx context.Context, msg T) or (msg T).","Move extra inputs into the message payload or read them from context/metadata inside the function body.","Use function structs with instance state instead of extra parameters for configuration values.","Wrap multi-argument logic in an adapter closure that conforms to the two-argument contract."],"exampleFix":"// before\nfunc handle(ctx context.Context, msg []byte, topic string) ([]byte, error) { ... }\n// after\nfunc handle(ctx context.Context, msg []byte) ([]byte, error) {\n    topic := ctx.Value(\"topic\").(string)\n    ...\n}","handlingStrategy":"validation","validationCode":"func validateHandlerSig(handler interface{}) error {\n    t := reflect.TypeOf(handler)\n    if t.Kind() != reflect.Func || t.NumIn() > 2 {\n        return errors.New(\"handler must take at most two arguments\")\n    }\n    return nil\n}\n// call before registering: validateHandlerSig(myHandler)","typeGuard":"func isValidHandler(handler interface{}) bool {\n    t := reflect.TypeOf(handler)\n    return t != nil && t.Kind() == reflect.Func && t.NumIn() <= 2\n}","tryCatchPattern":"f, err := pf.NewGoFunction(ctx, pf.GoFunction{\n    Handler: myHandler,\n})\nif err != nil {\n    log.Fatalf(\"function registration failed: %v\", err)\n}","preventionTips":["Stick to the canonical signatures: func(msg T) or func(ctx context.Context, msg T).","Inject extra data via message payload or context, never extra parameters.","Use struct-based instance functions for configuration/state instead of parameters.","Compile-time note: signatures are only checked at registration — test function startup in CI."],"tags":["go","pulsar-functions","reflection","function-signature"],"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-14T05:17:10.506Z"}