micro/go-micro · error
failed to marshal: %v is not type of *bytes.Frame or proto.M
Error message
failed to marshal: %v is not type of *bytes.Frame or proto.Message
What it means
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.
Source
Thrown at client/grpc/codec.go:76
if ok {
b.Data = data
return nil
}
return w.Codec.Unmarshal(data, v)
}
func (protoCodec) Marshal(v interface{}) ([]byte, error) {
switch m := v.(type) {
case *bytes.Frame:
return m.Data, nil
case proto.Message:
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"
}
View on GitHub (pinned to 24529f1404)
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")
Example fix
// before
client.Publish(ctx, topic, &MyPlainStruct{ID: 1})
// after
msg := &mypb.MyEvent{Id: 1}
client.Publish(ctx, topic, msg) // protobuf message Defensive patterns
Strategy: type-guard
Validate before calling
if !isProtoMessage(payload) {
return fmt.Errorf("grpc proto codec requires proto.Message, got %T", payload)
} Type guard
func isProtoMessage(v interface{}) bool {
_, ok := v.(proto.Message)
return ok
} Try / catch
if err := client.Publish(ctx, topic, payload); err != nil {
if strings.Contains(err.Error(), "is not type of *bytes.Frame or proto.Message") {
// switch payload to a generated pb type or change codec
}
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- failed to unmarshal: %v is not type of proto.Message
- 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/107328476bf5afe2.
Report an issue: GitHub.