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
- Cast to MapFieldAccessor (or get the map via GetValue) and mutate the returned IDictionary/MapField: Clear() then Add entries.
- In reflection code, special-case IsMap fields: read the map with GetValue and copy its entries instead of calling SetValue.
- Use IMessage.MergeFrom or the message's own cloning (e.g. message.Clone()) instead of per-field SetValue for copies.
- 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
- Never call SetValue on map fields; mutate the MapField via GetValue.
- Special-case IsMap in any generic reflection-based copy/serialization code.
- Prefer message.Clone()/MergeFrom over per-field SetValue for copying.
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
- SetValue is not implemented for repeated fields
- Dictionary has entry with null key
- FieldDescriptors can only be compared to other…
- EnumType is only valid for enum fields.
- MessageType is only valid for message fields.
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)