gin-gonic/gin · error

obj is not ProtoMessage

Error message

obj is not ProtoMessage

What it means

Returned by protobufBinding.BindBody (binding/protobuf.go:32) when the destination object does not implement google.golang.org/protobuf/proto.Message. Protobuf unmarshalling requires a concrete generated message so it knows the wire format; a plain struct or *string fails the type assertion.

Source

Thrown at binding/protobuf.go:32

type protobufBinding struct{}

func (protobufBinding) Name() string {
	return "protobuf"
}

func (b protobufBinding) Bind(req *http.Request, obj any) error {
	buf, err := io.ReadAll(req.Body)
	if err != nil {
		return err
	}
	return b.BindBody(buf, obj)
}

func (protobufBinding) BindBody(body []byte, obj any) error {
	msg, ok := obj.(proto.Message)
	if !ok {
		return errors.New("obj is not ProtoMessage")
	}
	if err := proto.Unmarshal(body, msg); err != nil {
		return err
	}
	// Here it's same to return validate(obj), but until now we can't add
	// `binding:""` to the struct which automatically generate by gen-proto
	return nil
	// return validate(obj)
}

View on GitHub (pinned to 34dac209ff)

Solutions

  1. Make sure the bind target is a pointer to a protoc-gen-go generated message, e.g. var msg pb.User; c.ShouldBindWith(&msg, binding.Protobuf).
  2. Regenerate the .pb.go files with the current google.golang.org/protobuf toolchain so the type satisfies proto.Message.
  3. Pass a pointer (&msg) — the unexported ProtoReflect method is only on the pointer receiver for most generated types.

Example fix

// before
var msg MyPlainStruct
c.ProtoBuf(http.StatusOK, &msg)
// after
var msg pb.MyMessage
c.ShouldBindWith(&msg, binding.Protobuf)
Defensive patterns

Strategy: type-guard

Validate before calling

var msg any = &pb.MyMessage{}
if _, ok := msg.(proto.Message); !ok {
    return fmt.Errorf("obj %T is not proto.Message", msg)
}

Type guard

func isProtoMessage(v any) bool {
    _, ok := v.(proto.Message)
    return ok
}

Try / catch

if err := c.ShouldBindWith(&msg, binding.Protobuf); err != nil {
    if err.Error() == "obj is not ProtoMessage" {
        // regenerate pb types or pass a pointer to a generated message
    }
}

Prevention

When it happens

Trigger: Calling c.ProtoBuf / binding.Protobuf.Bind with a struct that was not generated by protoc-gen-go (or is a pointer to one); passing a value instead of a pointer to the generated message.

Common situations: Using the older github.com/golang/protobuf/proto.Message alias with a new-style generated type; passing a hand-written struct; passing &someStruct{} instead of &pb.SomeMessage{}.

Related errors


AI-assisted analysis of gin-gonic/gin@34dac209ff (2026-08-04). Data as JSON: /data/errors/6f2c7dc3c9692c55.json. Report an issue: GitHub.