{"record":{"id":"41b7f51604fcfcfa","repo":"XINCGer/Unity3DTraining","slug":"expected-an-object-to-populate-a-map","errorCode":null,"errorMessage":"Expected an object to populate a map","messagePattern":"Expected an object to populate a map","errorType":"validation","errorClass":"InvalidProtocolBufferException","httpStatus":null,"severity":"error","filePath":"NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonParser.cs","lineNumber":277,"sourceCode":"                {\n                    return;\n                }\n                tokenizer.PushBack(token);\n                if (token.Type == JsonToken.TokenType.Null)\n                {\n                    throw new InvalidProtocolBufferException(\"Repeated field elements cannot be null\");\n                }\n                list.Add(ParseSingleValue(field, tokenizer));\n            }\n        }\n\n        private void MergeMapField(IMessage message, FieldDescriptor field, JsonTokenizer tokenizer)\n        {\n            // Map fields are always objects, even if the values are well-known types: ParseSingleValue handles those.\n            var token = tokenizer.Next();\n            if (token.Type != JsonToken.TokenType.StartObject)\n            {\n                throw new InvalidProtocolBufferException(\"Expected an object to populate a map\");\n            }\n\n            var type = field.MessageType;\n            var keyField = type.FindFieldByNumber(1);\n            var valueField = type.FindFieldByNumber(2);\n            if (keyField == null || valueField == null)\n            {\n                throw new InvalidProtocolBufferException(\"Invalid map field: \" + field.FullName);\n            }\n            IDictionary dictionary = (IDictionary)field.Accessor.GetValue(message);\n\n            while (true)\n            {\n                token = tokenizer.Next();\n                if (token.Type == JsonToken.TokenType.EndObject)\n                {\n                    return;\n                }","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/XINCGer/Unity3DTraining/blob/016f98412ea5e11756b286736f479b66ab6216d5/NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonParser.cs#L259-L295","documentation":"Google.Protobuf's JsonParser parses a proto3 map field strictly from a JSON object ({\"key\": value, ...}). When MergeMapField encounters any token other than '{' for a map field, it throws this InvalidProtocolBufferException. This mirrors the canonical protobuf JSON mapping where map fields must be represented as JSON objects.","triggerScenarios":"Calling JsonParser.Parse<T>(json) where a map<K,V> field is given a JSON array (e.g. [{...}]), a JSON array of key/value pairs, a string, a number, or null instead of a JSON object.","commonSituations":"Hand-written JSON payloads using array-of-entries notation for maps (a protobuf wire-format habit that is not valid canonical JSON); JSON produced by a non-canonical serializer that encodes maps as arrays; copy-pasted JSON from another serialization scheme (e.g. MessagePack-derived or MongoDB-style arrays).","solutions":["Rewrite the JSON so the map field is a JSON object: \"myMap\": {\"key1\": \"val1\", \"key2\": \"val2\"} instead of an array.","If the incoming JSON is array-encoded, pre-transform it to an object with a key extraction step before calling JsonParser.Parse.","If the field is semantically a repeated message (ordered list) rather than a map, change the proto schema from map<K,V> to repeated <entry-message>.","Catch InvalidProtocolBufferException around Parse and return a descriptive 400-style error identifying the malformed map field."],"exampleFix":"// before: array encoding rejected\n{\"myMap\": [{\"key\": \"a\", \"value\": 1}]}\n\n// after: object encoding accepted\n{\"myMap\": {\"a\": 1}}","handlingStrategy":"validation","validationCode":"// Ensure map fields are JSON objects before parsing\nfunction validateMapsAsObjects(payload) {\n  if (payload.myMap != null && (typeof payload.myMap !== 'object' || Array.isArray(payload.myMap))) {\n    throw new Error('myMap must be a JSON object, not an array or scalar');\n  }\n}\n// generic: if (Array.isArray(v)) v = Object.fromEntries(v.map(e => [e.key, e.value]));","typeGuard":"function isJsonObject(v) { return v !== null && typeof v === 'object' && !Array.isArray(v); }","tryCatchPattern":"try { var msg = JsonParser.Default.Parse<MyMessage>(json); }\ncatch (InvalidProtocolBufferException ex) { /* log ex.Message; return 400 malformed map field */ }","preventionTips":["Always serialize proto maps as JSON objects, never arrays of entries","Document the canonical JSON mapping for map fields in API contracts","Add JSON-schema validation that enforces type: object for map fields"],"tags":["protobuf","json-parsing","map-field","invalid-protocol-buffer"],"backgroundTag":"protobuf-unmarshal-failed","analyzedSha":"016f98412ea5e11756b286736f479b66ab6216d5","analyzedAt":"2026-09-12T01:08:58.711Z","contentChangedAt":"2026-09-12T01:08:58.711Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}