{"record":{"id":"b096ccc45792a2dc","repo":"hyperledger/fabric","slug":"receiver-t-s-does-not-return-a-an-implementor-of","errorCode":null,"errorMessage":"receiver %T.%s does not return a an implementor of proto.Message as its first return value","messagePattern":"receiver %T\\.(.+?) does not return a an implementor of proto\\.Message as its first return value","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/dispatcher/dispatcher.go","lineNumber":48,"sourceCode":"\tif method == (reflect.Value{}) {\n\t\treturn nil, errors.Errorf(\"receiver %T.%s does not exist\", receiver, methodName)\n\t}\n\n\tif method.Type().NumIn() != 1 {\n\t\treturn nil, errors.Errorf(\"receiver %T.%s has %d parameters but expected 1\", receiver, methodName, method.Type().NumIn())\n\t}\n\n\tinputType := method.Type().In(0)\n\tif inputType.Kind() != reflect.Pointer {\n\t\treturn nil, errors.Errorf(\"receiver %T.%s does not accept a pointer as its argument\", receiver, methodName)\n\t}\n\n\tif method.Type().NumOut() != 2 {\n\t\treturn nil, errors.Errorf(\"receiver %T.%s returns %d values but expected 2\", receiver, methodName, method.Type().NumOut())\n\t}\n\n\tif !method.Type().Out(0).Implements(reflect.TypeFor[proto.Message]()) {\n\t\treturn nil, errors.Errorf(\"receiver %T.%s does not return a an implementor of proto.Message as its first return value\", receiver, methodName)\n\t}\n\n\tif !method.Type().Out(1).Implements(reflect.TypeFor[error]()) {\n\t\treturn nil, errors.Errorf(\"receiver %T.%s does not return an error as its second return value\", receiver, methodName)\n\t}\n\n\tinputValue := reflect.New(inputType.Elem())\n\tinputMsg, ok := inputValue.Interface().(proto.Message)\n\tif !ok {\n\t\treturn nil, errors.Errorf(\"receiver %T.%s does not accept a proto.Message as its argument, it is '%T'\", receiver, methodName, inputValue.Interface())\n\t}\n\n\terr := d.Protobuf.Unmarshal(inputBytes, inputMsg)\n\tif err != nil {\n\t\treturn nil, errors.WithMessagef(err, \"could not decode input arg for %T.%s\", receiver, methodName)\n\t}\n\n\toutputVals := method.Call([]reflect.Value{inputValue})","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/dispatcher/dispatcher.go#L30-L66","documentation":"Dispatch requires the first of the method's two return values to implement proto.Message (google.golang.org/protobuf), because it marshals that value into the response bytes. This error is thrown when the first return type does not implement proto.Message.","triggerScenarios":"Calling Dispatch (via Invoke) on a method whose first return is a plain struct, string, []byte, or other non-proto type, e.g. func (s *Svc) Do(req *pb.Req) (MyResult, error).","commonSituations":"Handlers returning application-defined structs instead of generated protobuf types; mixing gogo/protobuf or legacy golang/protobuf types with the google.golang.org/protobuf runtime the dispatcher imports, so Implements(proto.Message) fails across mismatched runtimes.","solutions":["Change the first return value to a generated protobuf message type (*pb.SomeResponse).","Regenerate proto types with the same protobuf-go module (google.golang.org/protobuf) the dispatcher uses; remove gogo/protobuf or golang/protobuf mixing.","If a non-proto result is needed, serialize it into a field of a proto response wrapper message."],"exampleFix":"// before\nfunc (s *Svc) GetAsset(req *pb.GetRequest) (*Asset, error) { ... } // plain struct\n\n// after\nfunc (s *Svc) GetAsset(req *pb.GetRequest) (*pb.Asset, error) { ... } // generated proto type","handlingStrategy":"validation","validationCode":"func validateFirstReturnIsProto(receiver any, methodName string) error {\n    m := reflect.ValueOf(receiver).MethodByName(methodName)\n    if !m.IsValid() || m.Type().NumOut() != 2 {\n        return fmt.Errorf(\"method %s missing or wrong shape\", methodName)\n    }\n    if !m.Type().Out(0).Implements(reflect.TypeFor[proto.Message]()) {\n        return fmt.Errorf(\"method %s first return does not implement proto.Message\", methodName)\n    }\n    return nil\n}","typeGuard":"func firstReturnIsProtoMessage(receiver any, methodName string) bool {\n    m := reflect.ValueOf(receiver).MethodByName(methodName)\n    return m.IsValid() && m.Type().NumOut() >= 1 &&\n        m.Type().Out(0).Implements(reflect.TypeFor[proto.Message]())\n}","tryCatchPattern":null,"preventionTips":["Only return protoc-gen-go generated types from handlers.","Keep the proto runtime consistent: google.golang.org/protobuf everywhere; avoid gogo/protobuf or legacy golang/protobuf mixing.","Add interface assertions in tests: var _ proto.Message = (*pb.MyResponse)(nil)."],"tags":["go","reflection","proto","type-mismatch"],"backgroundTag":"handler-signature-mismatch","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}