{"record":{"id":"107328476bf5afe2","repo":"micro/go-micro","slug":"failed-to-marshal-v-is-not-type-of-bytes-frame","errorCode":null,"errorMessage":"failed to marshal: %v is not type of *bytes.Frame or proto.Message","messagePattern":"failed to marshal: (.+?) is not type of \\*bytes\\.Frame or proto\\.Message","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/grpc/codec.go","lineNumber":76,"sourceCode":"\tif ok {\n\t\tb.Data = data\n\t\treturn nil\n\t}\n\treturn w.Codec.Unmarshal(data, v)\n}\n\nfunc (protoCodec) Marshal(v interface{}) ([]byte, error) {\n\tswitch m := v.(type) {\n\tcase *bytes.Frame:\n\t\treturn m.Data, nil\n\tcase proto.Message:\n\t\treturn proto.Marshal(m)\n\tcase protoiface.MessageV1:\n\t\t// #2333 compatible with etcd legacy proto.Message\n\t\tm2 := protoimpl.X.ProtoMessageV2Of(m)\n\t\treturn proto.Marshal(m2)\n\t}\n\treturn nil, fmt.Errorf(\"failed to marshal: %v is not type of *bytes.Frame or proto.Message\", v)\n}\n\nfunc (protoCodec) Unmarshal(data []byte, v interface{}) error {\n\tswitch m := v.(type) {\n\tcase proto.Message:\n\t\treturn proto.Unmarshal(data, m)\n\tcase protoiface.MessageV1:\n\t\t// #2333 compatible with etcd legacy proto.Message\n\t\tm2 := protoimpl.X.ProtoMessageV2Of(m)\n\t\treturn proto.Unmarshal(data, m2)\n\t}\n\treturn fmt.Errorf(\"failed to unmarshal: %v is not type of proto.Message\", v)\n}\n\nfunc (protoCodec) Name() string {\n\treturn \"proto\"\n}\n","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/client/grpc/codec.go#L58-L94","documentation":"The gRPC client's proto codec Marshal was given a value that is neither *bytes.Frame, a v2 proto.Message, nor a v1 protoiface.MessageV1. The library only knows how to serialize protobuf messages over gRPC, so it refuses anything else instead of silently producing garbage.","triggerScenarios":"Calling client.Publish or a gRPC call with a request/response payload that is a plain Go struct, map, or JSON-marshalable type while the gRPC client is using the proto codec (the default Content-Type application/grpc+proto).","commonSituations":"Registering protobuf services but publishing events with plain structs; switching a service from the default (mucp/json) client to grpc without converting message types; generated pb types not imported so the payload stays a struct.","solutions":["Ensure request and response payloads are generated protobuf message types (protoc-gen-go)","Set the client Content-Type to application/grpc+json (or another supported codec) if you want to send non-proto payloads","Use *raw.Frame to send pre-encoded bytes","Check micro client options: client.ContentType(\"application/grpc+json\")"],"exampleFix":"// before\nclient.Publish(ctx, topic, &MyPlainStruct{ID: 1})\n// after\nmsg := &mypb.MyEvent{Id: 1}\nclient.Publish(ctx, topic, msg) // protobuf message","handlingStrategy":"type-guard","validationCode":"if !isProtoMessage(payload) {\n    return fmt.Errorf(\"grpc proto codec requires proto.Message, got %T\", payload)\n}","typeGuard":"func isProtoMessage(v interface{}) bool {\n    _, ok := v.(proto.Message)\n    return ok\n}","tryCatchPattern":"if err := client.Publish(ctx, topic, payload); err != nil {\n    if strings.Contains(err.Error(), \"is not type of *bytes.Frame or proto.Message\") {\n        // switch payload to a generated pb type or change codec\n    }\n}","preventionTips":["Generate and import pb types for all gRPC payloads","Keep client and server codecs aligned","Add round-trip codec tests in CI","Don't mix plain structs with the gRPC proto client"],"tags":["grpc","protobuf","codec","serialization"],"backgroundTag":"grpc-codec-type-mismatch","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}