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

  1. Regenerate the C# code with the current protoc/grpc-csharp plugin so the map entry type has key field 1 and value field 2.
  2. Verify the proto definition uses map<K,V> syntax rather than a hand-crafted entry message missing one of the two fields.
  3. Check descriptor construction code (if building descriptors at runtime) to ensure map_entry messages define both field numbers 1 and 2.
  4. 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

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


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)