{"record":{"id":"f7b3fe930abe4404","repo":"micro/go-micro","slug":"subscriber-v-v-returns-v-not-error","errorCode":null,"errorMessage":"subscriber %v.%v returns %v not error","messagePattern":"subscriber (.+?)\\.(.+?) returns (.+?) not error","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/grpc/subscriber.go","lineNumber":161,"sourceCode":"\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)\n\t\t\t}\n\t\t\tif method.Type.NumOut() != 1 {\n\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\"subscriber %v.%v has wrong number of outs: %v require signature %s\",\n\t\t\t\t\tname, method.Name, method.Type.NumOut(), subSig)\n\t\t\t}\n\t\t\tif returnType := method.Type.Out(0); returnType != typeOfError {\n\t\t\t\treturn fmt.Errorf(\"subscriber %v.%v returns %v not error\", name, method.Name, returnType.String())\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broker.Handler {\n\treturn func(p broker.Event) (err error) {\n\t\tdefer func() {\n\t\t\tif r := recover(); r != nil {\n\t\t\t\tg.opts.Logger.Log(logger.ErrorLevel, \"panic recovered: \", r)\n\t\t\t\tg.opts.Logger.Log(logger.ErrorLevel, string(debug.Stack()))\n\t\t\t\terr = errors.InternalServerError(\"go.micro.server\", \"panic recovered: %v\", r)\n\t\t\t}\n\t\t}()\n\n\t\tmsg := p.Message()","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/server/grpc/subscriber.go#L143-L179","documentation":"After checking the handler returns exactly one value, validateSubscriber verifies that the single return type is exactly the built-in `error` interface. If the handler returns something else (a custom error type, a string, a struct, etc.) registration fails with this message naming the offending return type.","triggerScenarios":"Registering a subscriber whose method returns a single value that is not of interface type `error`, e.g. `func (h *h) Handle(ctx context.Context, e *Event) *MyError` or returns a concrete error implementation or a status/bool.","commonSituations":"Handlers returning concrete custom error structs instead of the `error` interface; converting code from other frameworks where handlers return status objects or nothing.","solutions":["Change the return type to the built-in `error` interface: `func (h *h) Handle(ctx context.Context, e *Event) error`","If a custom error type carries extra data, return it wrapped as `error` (implement/assign to error) and unwrap at the call site"],"exampleFix":"// before\nfunc (h *handler) Handle(ctx context.Context, e *Event) *ValidationError { ... }\n// after\nfunc (h *handler) Handle(ctx context.Context, e *Event) error { ... }","handlingStrategy":"validation","validationCode":"func returnsError(fn interface{}) bool {\n\tt := reflect.TypeOf(fn)\n\tif t.NumOut() != 1 { return false }\n\terrIface := reflect.TypeOf((*error)(nil)).Elem()\n\treturn t.Out(0) == errIface\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Return the built-in `error` interface, never a concrete error struct type","If using a custom error type, return it as `error` and unwrap with errors.As in the caller","Add a compile-time assertion or lint rule that subscriber handlers match the required signature"],"tags":["grpc","subscriber","signature","go"],"backgroundTag":"subscriber-signature-mismatch","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}