{"record":{"id":"6be4bc150f4ba9aa","repo":"hyperledger/fabric","slug":"receiver-t-s-does-not-accept-a-proto-message-as","errorCode":null,"errorMessage":"receiver %T.%s does not accept a proto.Message as its argument, it is '%T'","messagePattern":"receiver %T\\.(.+?) does not accept a proto\\.Message as its argument, it is '%T'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/dispatcher/dispatcher.go","lineNumber":58,"sourceCode":"\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})\n\n\tif !outputVals[1].IsNil() {\n\t\treturn nil, outputVals[1].Interface().(error)\n\t}\n\n\tif outputVals[0].IsNil() {\n\t\treturn nil, errors.Errorf(\"receiver %T.%s returned (nil, nil) which is not allowed\", receiver, methodName)\n\t}\n\n\toutputMsg := outputVals[0].Interface().(proto.Message)","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/dispatcher/dispatcher.go#L40-L76","documentation":"Dispatch uses reflection to invoke a chaincode-receiver method whose input argument must implement proto.Message. After creating a new instance of the declared input type, it asserts that instance to proto.Message; if the assertion fails the method's input type is not a valid protobuf message, so the call cannot be dispatched.","triggerScenarios":"Registering/invoke-dispatching to a receiver method whose input parameter is a Go struct that does not embed/implement proto.Message (e.g. a plain struct or pointer-to-wrong-type), then calling Invoke on it.","commonSituations":"Hand-written chaincode receivers using custom argument structs instead of generated protobuf types; proto package version mismatches (google.golang.org/protobuf vs github.com/golang/protobuf) so the type no longer satisfies proto.Message; typos in generated code regeneration.","solutions":["Change the receiver method's input type to a generated protobuf message type that implements proto.Message","Regenerate protobuf code with protoc-gen-go so the struct implements the proto.Message interface (ProtoReflect method)","Ensure only one protobuf module version is imported so the interface assertion succeeds"],"exampleFix":"// before\nfunc (r *Receiver) DoThing(ctx context.Context, in *MyPlainStruct) (proto.Message, error)\n// after\nfunc (r *Receiver) DoThing(ctx context.Context, in *pb.MyThingRequest) (proto.Message, error)","handlingStrategy":"validation","validationCode":"var _ proto.Message = (*pb.MyThingRequest)(nil) // compile-time check before registering\nfunc validInput(m interface{}) bool {\n    _, ok := m.(proto.Message)\n    return ok\n}","typeGuard":"func isProtoMessage(v interface{}) bool {\n    _, ok := v.(proto.Message)\n    return ok\n}","tryCatchPattern":null,"preventionTips":["Add compile-time interface assertions (var _ proto.Message = (*T)(nil)) for all receiver input types","Use protoc-gen-go to generate all message types; never hand-roll them","Pin a single protobuf module version across the project"],"tags":["reflection","protobuf","chaincode","dispatcher"],"backgroundTag":"type-does-not-implement-interface","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"}