{"record":{"id":"609b5aab0fec966e","repo":"micro/go-micro","slug":"subscriber-v-returns-v-not-error","errorCode":null,"errorMessage":"subscriber %v returns %v not error","messagePattern":"subscriber (.+?) returns (.+?) not error","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/grpc/subscriber.go","lineNumber":135,"sourceCode":"\tvar argType reflect.Type\n\n\tif typ.Kind() == reflect.Func {\n\t\tname := \"Func\"\n\t\tswitch typ.NumIn() {\n\t\tcase 2:\n\t\t\targType = typ.In(1)\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"subscriber %v takes wrong number of args: %v required signature %s\", name, typ.NumIn(), subSig)\n\t\t}\n\t\tif !isExportedOrBuiltinType(argType) {\n\t\t\treturn fmt.Errorf(\"subscriber %v argument type not exported: %v\", name, argType)\n\t\t}\n\t\tif typ.NumOut() != 1 {\n\t\t\treturn fmt.Errorf(\"subscriber %v has wrong number of outs: %v require signature %s\",\n\t\t\t\tname, typ.NumOut(), subSig)\n\t\t}\n\t\tif returnType := typ.Out(0); returnType != typeOfError {\n\t\t\treturn fmt.Errorf(\"subscriber %v returns %v not error\", name, returnType.String())\n\t\t}\n\t} else {\n\t\thdlr := reflect.ValueOf(sub.Subscriber())\n\t\tname := reflect.Indirect(hdlr).Type().Name()\n\n\t\tfor m := 0; m < typ.NumMethod(); m++ {\n\t\t\tmethod := typ.Method(m)\n\n\t\t\tswitch method.Type.NumIn() {\n\t\t\tcase 3:\n\t\t\t\targType = method.Type.In(2)\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"subscriber %v.%v takes wrong number of args: %v required signature %s\",\n\t\t\t\t\tname, method.Name, method.Type.NumIn(), subSig)\n\t\t\t}\n\n\t\t\tif !isExportedOrBuiltinType(argType) {\n\t\t\t\treturn fmt.Errorf(\"%v argument type not exported: %v\", name, argType)","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/server/grpc/subscriber.go#L117-L153","documentation":"Beyond returning exactly one value, a subscriber's single return must be the built-in error interface type. validateSubscriber compares typ.Out(0) against typeOfError (reflect.TypeOf((*error)(nil)).Elem()) and rejects anything else, because the dispatcher type-asserts the first return value to error (returnValues[0].Interface().(error)).","triggerScenarios":"Registering a subscriber whose sole return is a concrete type or other interface, e.g. func(ctx context.Context, e *T) *MyError, or returns a custom error interface, string, or bool instead of error.","commonSituations":"Handlers written with a project-specific error type for consistency with internal APIs; refactoring that replaced error with a wrapped result type; porting handlers from frameworks that allow arbitrary returns.","solutions":["Change the return to the standard error interface: ... error.","Wrap custom error types in error on return (return myErr where myErr implements error, or fmt.Errorf with %w).","Return nil explicitly when there is no failure.","If you need rich failure info, attach it to a custom error type that satisfies the error interface rather than changing the return type."],"exampleFix":"// before\nfunc(ctx context.Context, e *pb.Event) *EventError { ... }\n// after\nfunc(ctx context.Context, e *pb.Event) error { ...; return &EventError{...} }","handlingStrategy":"validation","validationCode":"func returnsStdError(fn interface{}) bool {\n\tt := reflect.TypeOf(fn)\n\tif t == nil || t.Kind() == reflect.Func && t.NumOut() != 1 { return false }\n\treturn t.NumOut() == 1 && t.Out(0) == reflect.TypeOf((*error)(nil)).Elem()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only ever return the built-in error interface from subscribers.","Custom error types may be returned as values of type error, not as their own type.","Avoid project-specific result/error wrapper types as subscriber return values.","Add a compile-time assertion: var _ func(context.Context, *pb.Event) error = myHandler."],"tags":["go","grpc","subscriber","error-handling","handler-signature"],"backgroundTag":"invalid-handler-signature","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}