micro/go-micro · error

failed to marshal: is not type of *bytes.Frame or…

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.

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.

Appendix: 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)