XINCGer/Unity3DTraining · error · InvalidOperationException

SetValue is not implemented for map fields

Error message

SetValue is not implemented for map fields

What it means

Map fields in Google.Protobuf have no single-value setter: their content is managed through the MapField<TKey,TValue> collection returned by the property getter. MapFieldAccessor.SetValue intentionally throws InvalidOperationException because assigning a whole map object is not a supported operation.

Solutions

  1. Cast to MapFieldAccessor (or get the map via GetValue) and mutate the returned IDictionary/MapField: Clear() then Add entries.
  2. In reflection code, special-case IsMap fields: read the map with GetValue and copy its entries instead of calling SetValue.
  3. Use IMessage.MergeFrom or the message's own cloning (e.g. message.Clone()) instead of per-field SetValue for copies.
  4. Check accessor.IsMap before invoking SetValue and branch accordingly.

Example fix

// before
accessor.SetValue(message, sourceMapObject); // throws for map fields
// after
var target = (IDictionary)accessor.GetValue(message);
target.Clear();
foreach (var key in ((IDictionary)sourceMapObject).Keys) target[key] = ((IDictionary)sourceMapObject)[key];
Defensive patterns

Strategy: type-guard

Validate before calling

if (accessor is MapFieldAccessor) { /* use GetValue + IDictionary mutation */ }

Type guard

bool IsMapField(IFieldAccessor a) => a is MapFieldAccessor;

Try / catch

try { accessor.SetValue(msg, v); } catch (InvalidOperationException e) when (e.Message.Contains("map fields")) { CopyMapEntries((IDictionary)accessor.GetValue(msg), v); }

Prevention

When it happens

Trigger: Calling reflection-based SetValue(message, value) on a field descriptor whose accessor is a MapFieldAccessor — e.g. generic reflection/serialization code that writes every field via SetValue, or copying messages field-by-field via descriptors.

Common situations: Custom object mappers or JSON/O-RM style code that uses IFieldAccessor.SetValue uniformly for all fields; test helpers that clone messages generically; porting code from runtimes where map setters exist.

Related errors


AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12). Data as JSON: /api/errors/5d191205952ccacb. Report an issue: GitHub.

Appendix: source

Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/Reflection/MapFieldAccessor.cs:56

{
    /// <summary>
    /// Accessor for map fields.
    /// </summary>
    internal sealed class MapFieldAccessor : FieldAccessorBase
    {
        internal MapFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
        {
        }

        public override void Clear(IMessage message)
        {
            IDictionary list = (IDictionary) GetValue(message);
            list.Clear();
        }

        public override void SetValue(IMessage message, object value)
        {
            throw new InvalidOperationException("SetValue is not implemented for map fields");
        }
    }
}

View on GitHub (pinned to 016f98412e)