micro/go-micro · error
failed to unmarshal: %v is not type of proto.Message
Error message
failed to unmarshal: %v is not type of proto.Message
What it means
The proto codec Unmarshal received bytes and a destination value that is not a proto.Message (v2) or MessageV1 (legacy). gRPC responses must decode into protobuf message pointers; anything else cannot be filled by proto.Unmarshal.
Source
Thrown at client/grpc/codec.go:88
return proto.Marshal(m)
case protoiface.MessageV1:
// #2333 compatible with etcd legacy proto.Message
m2 := protoimpl.X.ProtoMessageV2Of(m)
return proto.Marshal(m2)
}
return nil, fmt.Errorf("failed to marshal: %v is not type of *bytes.Frame or proto.Message", v)
}
func (protoCodec) Unmarshal(data []byte, v interface{}) error {
switch m := v.(type) {
case proto.Message:
return proto.Unmarshal(data, m)
case protoiface.MessageV1:
// #2333 compatible with etcd legacy proto.Message
m2 := protoimpl.X.ProtoMessageV2Of(m)
return proto.Unmarshal(data, m2)
}
return fmt.Errorf("failed to unmarshal: %v is not type of proto.Message", v)
}
func (protoCodec) Name() string {
return "proto"
}
func (bytesCodec) Marshal(v interface{}) ([]byte, error) {
b, ok := v.(*[]byte)
if !ok {
return nil, fmt.Errorf("failed to marshal: %v is not type of *[]byte", v)
}
return *b, nil
}
func (bytesCodec) Unmarshal(data []byte, v interface{}) error {
b, ok := v.(*[]byte)
if !ok {
return fmt.Errorf("failed to unmarshal: %v is not type of *[]byte", v)View on GitHub (pinned to 24529f1404)
Solutions
- Pass a pointer to a generated protobuf message as the response (e.g. &pb.GetResponse{})
- Switch the client/service Content-Type to a non-proto codec if payloads are not protobuf
- Regenerate protobuf bindings with protoc if handlers use outdated types
- Check that both client and server agree on application/grpc+proto
Example fix
// before
var resp map[string]interface{}
client.Call(ctx, req, &resp)
// after
resp := &mypb.GetResponse{}
client.Call(ctx, req, resp) Defensive patterns
Strategy: type-guard
Validate before calling
var resp pb.GetResponse
if _, ok := interface{}(&resp).(proto.Message); !ok {
return fmt.Errorf("response target must be proto.Message")
} Type guard
func isProtoMessagePtr(v interface{}) bool {
m, ok := v.(proto.Message)
return ok && m != nil
} Try / catch
err := client.Call(ctx, req, resp)
if err != nil && strings.Contains(err.Error(), "failed to unmarshal") {
// resp is not proto.Message: fix the response type or codec
} Prevention
- Always pass &pb.Response{} pointers as call targets
- Regenerate pb bindings after .proto changes
- Keep server/client Content-Types identical
- Type-check payload targets in wrapper helpers
When it happens
Trigger: Making a gRPC call where the response prototype passed to the client is a plain struct, map, or *interface{} instead of a generated protobuf message pointer, while the codec is proto.
Common situations: Using grpc.NewClient but building requests/responses manually with non-pb types; code migrated from a JSON client where resp was a plain struct; forgotten protoc regeneration so the handler uses the wrong type.
Related errors
- failed to marshal: %v is not type of *bytes.Frame or proto.M
- failed to marshal: %v is not type of *[]byte
- failed to unmarshal: %v is not type of *[]byte
- ErrInvalidMessage
- unknown request path
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/cb0141f154b0d320.
Report an issue: GitHub.