XINCGer/Unity3DTraining · error · InvalidProtocolBufferException
Invalid map field:
Error message
Invalid map field:
What it means
During map parsing, JsonParser looks up the map entry's key field (number 1) and value field (number 2) on the map entry message type. If either is missing, the field's schema is not a well-formed map entry, and this exception names the offending field via field.FullName. This indicates a descriptor-level problem, not a problem with the JSON input.
Solutions
- Regenerate the C# code with the current protoc/grpc-csharp plugin so the map entry type has key field 1 and value field 2.
- Verify the proto definition uses map<K,V> syntax rather than a hand-crafted entry message missing one of the two fields.
- Check descriptor construction code (if building descriptors at runtime) to ensure map_entry messages define both field numbers 1 and 2.
- Ensure the Google.Protobuf NuGet package version matches the version the generated code was produced with.
Example fix
// before: hand-built map entry missing value field
new MessageProto { Name = "MyMapEntry", Fields = { FieldNum1Only } }
// after: regenerate or add both fields
message MyMapEntry { K key = 1; V value = 2; } // via map<K,V> in the parent message Defensive patterns
Strategy: validation
Validate before calling
// Sanity-check generated descriptors at startup
var field = MyMessage.Descriptor.FindFieldByName("myMap");
if (field?.MessageType.FindFieldByNumber(1) == null || field?.MessageType.FindFieldByNumber(2) == null)
throw new InvalidOperationException($"Malformed map entry for {field?.FullName}: fields 1/2 missing"); Try / catch
try { var msg = JsonParser.Default.Parse<T>(json); }
catch (InvalidProtocolBufferException ex) { throw new SchemaIntegrityException(ex.Message); } Prevention
- Always regenerate generated code with the same protoc version as the Google.Protobuf package
- Never hand-edit generated *_Grpc.cs / *Reflection.cs files
- Use map<K,V> syntax instead of hand-crafted map entry messages
When it happens
Trigger: Parsing JSON for a message whose field descriptor is marked as a map but whose generated entry type lacks fields 1 and 2 — typically from hand-built descriptors, corrupted/mismatched generated code, or a custom FieldRegistry/CustomTypeRegistry hack, not from standard generated C# code.
Common situations: Mixing generated code from different proto file versions where the map entry message was edited; dynamically constructed descriptors (DescriptorProto with a map entry missing field 1 or 2); binary/plugin-generated descriptors that bypass protoc validation.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Unhandled dictionary key type:
- Expected an object to populate a map
- Map values must not be null
- " " is already defined (as something other than a package)…
- " " is already defined in file " ".
AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12).
Data as JSON: /api/errors/b22bb8943349659e.
Report an issue: GitHub.
Appendix: source
Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonParser.cs:285
list.Add(ParseSingleValue(field, tokenizer));
}
}
private void MergeMapField(IMessage message, FieldDescriptor field, JsonTokenizer tokenizer)
{
// Map fields are always objects, even if the values are well-known types: ParseSingleValue handles those.
var token = tokenizer.Next();
if (token.Type != JsonToken.TokenType.StartObject)
{
throw new InvalidProtocolBufferException("Expected an object to populate a map");
}
var type = field.MessageType;
var keyField = type.FindFieldByNumber(1);
var valueField = type.FindFieldByNumber(2);
if (keyField == null || valueField == null)
{
throw new InvalidProtocolBufferException("Invalid map field: " + field.FullName);
}
IDictionary dictionary = (IDictionary)field.Accessor.GetValue(message);
while (true)
{
token = tokenizer.Next();
if (token.Type == JsonToken.TokenType.EndObject)
{
return;
}
object key = ParseMapKey(keyField, token.StringValue);
object value = ParseSingleValue(valueField, tokenizer);
if (value == null)
{
throw new InvalidProtocolBufferException("Map values must not be null");
}
dictionary[key] = value;
}View on GitHub (pinned to 016f98412e)