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

  1. Ensure request and response payloads are generated protobuf message types (protoc-gen-go)
  2. Set the client Content-Type to application/grpc+json (or another supported codec) if you want to send non-proto payloads
  3. Use *raw.Frame to send pre-encoded bytes
  4. 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

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


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/107328476bf5afe2. Report an issue: GitHub.