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
- 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).
- Regenerate the .pb.go files with the current google.golang.org/protobuf toolchain so the type satisfies proto.Message.
- 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
- Always pass a pointer to a protoc-gen-go generated message (&pb.X{}).
- Regenerate .pb.go with google.golang.org/protobuf when upgrading the toolchain.
- Add a compile-time check: var _ proto.Message = (*pb.MyMessage)(nil).
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
- unknown type
- can not convert to map slices of strings
- can not convert to map of strings
- invalid request
- unsupported field type for multipart.FileHeader
AI-assisted analysis of gin-gonic/gin@34dac209ff (2026-08-04).
Data as JSON: /data/errors/6f2c7dc3c9692c55.json.
Report an issue: GitHub.