{"record":{"id":"ab269d2015c8c0f1","repo":"grpc-ecosystem/grpc-gateway","slug":"unable-to-unmarshal-non-proto-field","errorCode":null,"errorMessage":"unable to unmarshal non proto field","messagePattern":"unable to unmarshal non proto field","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"runtime/marshal_proto.go","lineNumber":31,"sourceCode":"// ContentType always returns \"application/octet-stream\".\nfunc (*ProtoMarshaller) ContentType(_ interface{}) string {\n\treturn \"application/octet-stream\"\n}\n\n// Marshal marshals \"value\" into Proto\nfunc (*ProtoMarshaller) Marshal(value interface{}) ([]byte, error) {\n\tmessage, ok := value.(proto.Message)\n\tif !ok {\n\t\treturn nil, errors.New(\"unable to marshal non proto field\")\n\t}\n\treturn proto.Marshal(message)\n}\n\n// Unmarshal unmarshals proto \"data\" into \"value\"\nfunc (*ProtoMarshaller) Unmarshal(data []byte, value interface{}) error {\n\tmessage, ok := value.(proto.Message)\n\tif !ok {\n\t\treturn errors.New(\"unable to unmarshal non proto field\")\n\t}\n\treturn proto.Unmarshal(data, message)\n}\n\n// NewDecoder returns a Decoder which reads proto stream from \"reader\".\nfunc (marshaller *ProtoMarshaller) NewDecoder(reader io.Reader) Decoder {\n\treturn DecoderFunc(func(value interface{}) error {\n\t\tbuffer, err := io.ReadAll(reader)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn marshaller.Unmarshal(buffer, value)\n\t})\n}\n\n// NewEncoder returns an Encoder which writes proto stream into \"writer\".\nfunc (marshaller *ProtoMarshaller) NewEncoder(writer io.Writer) Encoder {\n\treturn EncoderFunc(func(value interface{}) error {","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/grpc-ecosystem/grpc-gateway/blob/a58a4436a376a4bcc7d8f10c4d4f919a8438bba9/runtime/marshal_proto.go#L13-L49","documentation":"ProtoMarshaller.Unmarshal requires the destination value to implement proto.Message. If the caller passes any other type (a plain struct, map, interface pointing elsewhere), it returns \"unable to unmarshal non proto field\" instead of attempting proto.Unmarshal, which would panic or fail. This guards the proto decoding path used for application/proto request bodies.","triggerScenarios":"Calling ProtoMarshaller.Unmarshal(data, value) where value is not a proto.Message — e.g. decoding a request into a custom struct, a map, or a double pointer that does not satisfy the proto.Message interface.","commonSituations":"Custom HTTP handlers reusing the proto marshaller to decode non-proto bodies; writing middleware that decodes into generic structs; tests (like TestProtoMarshalUnmarshal) passing wrong argument types by mistake; switching a route from JSON to proto content type without changing the decode target.","solutions":["Pass a pointer to a generated proto message (e.g. &pb.MyRequest{}) as the value.","For JSON/plain bodies use the JSONPb marshaller instead.","Verify the value implements proto.Message via a proto.Message type assertion before calling Unmarshal.","Fix middleware/handler code that decodes with the wrong marshaller for the content type."],"exampleFix":"// before\nvar req map[string]interface{}\nerr := protoMarshaller.Unmarshal(data, &req)\n// after\nreq := &pb.MyRequest{}\nerr := protoMarshaller.Unmarshal(data, req)","handlingStrategy":"type-guard","validationCode":"if _, ok := value.(proto.Message); !ok {\n    return fmt.Errorf(\"cannot unmarshal into %T; destination must implement proto.Message\", value)\n}","typeGuard":"func canUnmarshalProto(value interface{}) bool {\n    _, ok := value.(proto.Message)\n    return ok\n}","tryCatchPattern":"err := marshaller.Unmarshal(data, value)\nif err != nil {\n    if err.Error() == \"unable to unmarshal non proto field\" {\n        return fmt.Errorf(\"destination must be a proto message, got %T\", value)\n    }\n    return err\n}","preventionTips":["Decode requests into pointers to generated proto request types only.","Use JSONPb (or runtime.JSONPb{}) for non-proto request bodies.","Type-assert to proto.Message in middleware before delegating to the proto marshaller."],"tags":["grpc-gateway","marshalling","protobuf","unmarshal"],"backgroundTag":"invalid-marshaler-type","analyzedSha":"a58a4436a376a4bcc7d8f10c4d4f919a8438bba9","analyzedAt":"2026-09-02T10:28:31.537Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T16:17:10.729Z"}