{"record":{"id":"2f9d0cc12e789a64","repo":"apache/pulsar","slug":"function-returns-two-values-but-the-second-does-n","errorCode":null,"errorMessage":"function returns two values, but the second does not implement error","messagePattern":"function returns two values, but the second does not implement error","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pulsar-function-go/pf/function.go","lineNumber":86,"sourceCode":"\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) {\n\t\t\treturn fmt.Errorf(\"function returns a single value, but it does not implement error\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc newFunction(inputFunc interface{}) function {\n\tif inputFunc == nil {\n\t\treturn errorHandler(fmt.Errorf(\"function is nil\"))\n\t}\n\thandler := reflect.ValueOf(inputFunc)\n\thandlerType := reflect.TypeOf(inputFunc)\n\tif handlerType.Kind() != reflect.Func {\n\t\treturn errorHandler(fmt.Errorf(\"function kind %s is not %s\", handlerType.Kind(), reflect.Func))","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-function-go/pf/function.go#L68-L104","documentation":"For two-value handlers, the second return value must implement the error interface — the framework's (result, error) convention mirrors idiomatic Go. Reflection checks handler.Out(1).Implements(errorType); anything else (string, custom non-error type) fails registration.","triggerScenarios":"A handler like func(ctx context.Context, msg []byte) ([]byte, string) or ([]byte, MyStatus) is registered; NumOut()==2 but Out(1) does not implement error.","commonSituations":"Returning a status/error code string instead of error; returning (value, value) pairs; custom error-like struct that does not implement the built-in error interface; accidentally swapping return order.","solutions":["Make the second return value type error (return nil on success).","Define custom error types so they implement error (add an Error() string method).","If the second value is data, reorder so data is first and error second, or drop it.","Wrap error-code strings into errors.New / fmt.Errorf."],"exampleFix":"// before\nfunc handle(ctx context.Context, msg []byte) ([]byte, string) { ... }\n// after\nfunc handle(ctx context.Context, msg []byte) ([]byte, error) {\n    if bad { return nil, fmt.Errorf(\"bad message\") }\n    ...\n}","handlingStrategy":"type-guard","validationCode":"func secondReturnIsError(handler interface{}) bool {\n    t := reflect.TypeOf(handler)\n    errType := reflect.TypeOf((*error)(nil)).Elem()\n    return t.Kind() == reflect.Func && t.NumOut() == 2 && t.Out(1).Implements(errType)\n}","typeGuard":"func hasErrorSecond(handler interface{}) bool {\n    t := reflect.TypeOf(handler)\n    errType := reflect.TypeOf((*error)(nil)).Elem()\n    return t.NumOut() > 1 && t.Out(1).Implements(errType)\n}","tryCatchPattern":"f, err := pf.NewGoFunction(ctx, pf.GoFunction{\n    Handler: myHandler,\n})\nif err != nil {\n    if strings.Contains(err.Error(), \"second does not implement error\") {\n        log.Fatalf(\"change second return value to type error: %v\", err)\n    }\n    log.Fatalf(\"function registration failed: %v\", err)\n}","preventionTips":["Always end handler signatures with error as the last return value.","Make custom error types implement Error() string so they satisfy the error interface.","Never return status strings or code ints in the error position.","Grep handlers for return statements missing a trailing error during code review."],"tags":["go","pulsar-functions","reflection","error-handling"],"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"}