{"record":{"id":"f4d43977f2e132b5","repo":"grpc-ecosystem/grpc-gateway","slug":"unable-to-marshal-non-proto-field","errorCode":null,"errorMessage":"unable to marshal non proto field","messagePattern":"unable to marshal non proto field","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"runtime/marshal_proto.go","lineNumber":22,"sourceCode":"\t\"errors\"\n\t\"io\"\n\n\t\"google.golang.org/protobuf/proto\"\n)\n\n// ProtoMarshaller is a Marshaller which marshals/unmarshals into/from serialize proto bytes\ntype ProtoMarshaller struct{}\n\n// 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 {","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/grpc-ecosystem/grpc-gateway/blob/a58a4436a376a4bcc7d8f10c4d4f919a8438bba9/runtime/marshal_proto.go#L4-L40","documentation":"ProtoMarshaller.Marshal only accepts values implementing the proto.Message interface; if the runtime.Marshaler receives anything else (string, struct, map, json.RawMessage, etc.) it returns \"unable to marshal non proto field\". This marshaller is meant for endpoints configured with the proto content type (application/proto), so passing a non-proto value to it is a programming/configuration error.","triggerScenarios":"Calling runtime.Marshaler.Marshal (or serving a route configured with runtime.ProtoMarshaller{}) with a value that does not implement proto.Message — e.g. passing an HTTP handler's struct, a map, or a pointer to a non-proto type into runtime.Marshal/ServeContent with the proto marshaller.","commonSituations":"Writing a custom HTTP handler that mixes the JSON marshaller and proto marshaller incorrectly; wrapping generated handlers with custom code that passes a plain struct; using runtime.ServeContent/HTTPBody with a non-message argument on a proto-configured server.","solutions":["Ensure the value passed to Marshal implements proto.Message (use generated types like *pb.MyResponse).","If returning JSON, use the JSONPb marshaller instead of ProtoMarshaller.","When writing custom handlers, obtain the proto message first (e.g. from the generated handler or by constructing the pb type) before marshalling.","Check mux/route configuration so the right marshaler is registered for the content type."],"exampleFix":"// before\nvar resp map[string]interface{} = ...\ndata, err := protoMarshaller.Marshal(resp)\n// after\nresp := &pb.MyResponse{Name: \"x\"}\ndata, err := protoMarshaller.Marshal(resp)","handlingStrategy":"type-guard","validationCode":"if _, ok := v.(proto.Message); !ok {\n    return fmt.Errorf(\"%T does not implement proto.Message; use JSONPb for JSON output\", v)\n}","typeGuard":"func isProtoMessage(v interface{}) bool {\n    _, ok := v.(proto.Message)\n    return ok\n}","tryCatchPattern":"data, err := marshaller.Marshal(value)\nif err != nil {\n    if err.Error() == \"unable to marshal non proto field\" {\n        return fmt.Errorf(\"use JSONPb for non-proto values (%T)\", value)\n    }\n    return err\n}","preventionTips":["Only pass generated pb.* types to the proto marshaller.","Register JSONPb for application/json and ProtoMarshaller for application/proto on the mux.","In custom handlers, construct the proto message before marshalling the response."],"tags":["grpc-gateway","marshalling","protobuf","http-handler"],"backgroundTag":"invalid-marshaler-type","analyzedSha":"a58a4436a376a4bcc7d8f10c4d4f919a8438bba9","analyzedAt":"2026-09-02T10:28:31.537Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T16:17:10.729Z"}