1 year ago

#365606

test-img

Charlicopter

protobuf-net serialize exception: "Key already in the list". Rarely thrown

It's rare, but there's an occasional error caught by the Serializer.Serialize<SaveFile>(...) catch block: "Key already in the list". That's it. Just that message.

I'm performing basic serialization and deserialization of video game save files using Protobuf-Net. The data model is relatively simple: Just some ProtoMember fields, including a dictionary and some ProtoContracted data-objects with their own ProtoMembers, including a dictionary.

public enum AchievementID : int
{
    TEST,
    TEST2,
    TEST3,
};

public enum SlotSelect
{
    None,
    Slot1,
    Slot2,
    Slot3
}
    
[ProtoContract(SkipConstructor = true)]
public class GameNode_SaveState
{
    [ProtoMember(1)] public float[] StateFloats_Local { get; } = new float[32];
}

[ProtoContract(SkipConstructor = true)]
public class Achievement_SaveFile
{
    [ProtoMember(1)] public AchievementID ID { get; set; }
    [ProtoMember(2)] public string Name { get; set; }
    [ProtoMember(3)] public string Description { get; set; }
    [ProtoMember(4)] public bool HasBeenAchieved { get; set; }
}

[ProtoContract]
public struct GameNode_LoadingIndex
{
    [ProtoMember(1)] public int Target_TopGroup { get; set; }
    [ProtoMember(2)] public int Target_SubGroup { get; set; }
    [ProtoMember(3)] public int Target_LevelGroup { get; set; }
    [ProtoMember(4)] public int Target_Stage { get; set; }
}

[ProtoContract]
public class SaveFile
{
    [ProtoMember(1)] public uint Version { get; private set; }

    [ProtoMember(2)] public SaveSlot Slot1 { get; private set; }
    [ProtoMember(3)] public SaveSlot Slot2 { get; private set; }
    [ProtoMember(4)] public SaveSlot Slot3 { get; private set; }

    [ProtoMember(5)] public float[] Values { get; private set; }

    [ProtoMember(6)] public DateTime Timestamp { get; set; }

    [ProtoMember(7)] public Dictionary<AchievementID, Achievement_SaveFile> Achievements { get; private set; }

    public SaveFile() { }

    public SaveFile(uint version)
    {
        Version = version;
        Timestamp = DateTime.Now;
        Achievements = new Dictionary<AchievementID, Achievement_SaveFile>(); 

        Values = new float[64];
        Slot1 = new SaveSlot(SlotSelect.Slot1);
        Slot2 = new SaveSlot(SlotSelect.Slot1);
        Slot3 = new SaveSlot(SlotSelect.Slot1);
    }
}

[ProtoContract(SkipConstructor = true)]
public class SaveSlot
{
    [ProtoMember(1)] public SlotSelect SlotNumber { get; private set; }
    [ProtoMember(2)] public bool IsFresh { get; set; }
    [ProtoMember(3)] public GameNode_LoadingIndex SavedLoadingIndex { get; set; }
    [ProtoMember(4)] public Dictionary<GameNode_LoadingIndex, GameNode_SaveState> GameNodeSaveStates { get; private set; }
    [ProtoMember(5)] public float[] Values { get; private set; }

    public SaveSlot(SlotSelect slotNumber) 
    {
        SlotNumber = slotNumber; 
        SavedLoadingIndex = new GameNode_LoadingIndex();
        GameNodeSaveStates = new Dictionary<GameNode_LoadingIndex, GameNode_SaveState>(); 
    }
}
await Task.Run(() =>
{
    Debug.Log("Saving via ProtoBuf...");
    try
    {
        using (FileStream filestream = File.Create(filepath_local))
        {
            Serializer.Serialize(filestream, saveFile_outgoingCopy);
        }
    }
    catch (Exception e)
    {
        Debug.LogError($"File save failed (Exception): {e.Message}");
    }
});

The serialization process completes successfully about 99% of the time, but it does indeed fail from time to time.

The error is as follows:

File save failed (Exception): System.ArgumentException: Key already in the list
Parameter name: key
  at System.Runtime.CompilerServices.ConditionalWeakTable`2[TKey,TValue].Add (TKey key, TValue value) [0x000a8] in <6073cf49ed704e958b8a66d540dea948>:0 
  at System.Buffers.TlsOverPerCoreLockedStacksArrayPool`1[T].Return (T[] array, System.Boolean clearArray) [0x00071] in <6073cf49ed704e958b8a66d540dea948>:0 
  at ProtoBuf.BufferPool.ReleaseBufferToPool (System.Byte[]& buffer) [0x00009] in /_/src/protobuf-net.Core/BufferPool.cs:61 
  at ProtoBuf.BufferPool.ResizeAndFlushLeft (System.Byte[]& buffer, System.Int32 toFitAtLeastBytes, System.Int32 copyFromIndex, System.Int32 copyBytes) [0x00040] in /_/src/protobuf-net.Core/BufferPool.cs:51 
  at ProtoBuf.ProtoWriter+StreamProtoWriter.TryFlushOrResize (System.Int32 required, ProtoBuf.ProtoWriter+StreamProtoWriter writer, ProtoBuf.ProtoWriter+State& state) [0x0001c] in /_/src/protobuf-net.Core/ProtoWriter.Stream.cs:118 
  at ProtoBuf.ProtoWriter+StreamProtoWriter.DemandSpace (System.Int32 required, ProtoBuf.ProtoWriter+StreamProtoWriter writer, ProtoBuf.ProtoWriter+State& state) [0x00012] in /_/src/protobuf-net.Core/ProtoWriter.Stream.cs:105 
  at ProtoBuf.ProtoWriter+StreamProtoWriter.ImplWriteVarint32 (ProtoBuf.ProtoWriter+State& state, System.UInt32 value) [0x00000] in /_/src/protobuf-net.Core/ProtoWriter.Stream.cs:274 
  at ProtoBuf.ProtoWriter+State.WriteHeaderCore (System.Int32 fieldNumber, ProtoBuf.WireType wireType) [0x00008] in /_/src/protobuf-net.Core/ProtoWriter.State.WriteMethods.cs:715 
  at ProtoBuf.ProtoWriter+State.WriteFieldHeader (System.Int32 fieldNumber, ProtoBuf.WireType wireType) [0x00043] in /_/src/protobuf-net.Core/ProtoWriter.State.WriteMethods.cs:79 
  at ProtoBuf.Serializers.RepeatedSerializer`2[TCollection,TItem].Write[TEnumerator] (ProtoBuf.ProtoWriter+State& state, System.Int32 fieldNumber, ProtoBuf.Serializers.SerializerFeatures category, ProtoBuf.WireType wireType, TEnumerator& values, ProtoBuf.Serializers.ISerializer`1[T] serializer) [0x00030] in /_/src/protobuf-net.Core/Serializers/RepeatedSerializer.cs:162 
  at ProtoBuf.Serializers.VectorSerializer`1[T].Write (ProtoBuf.ProtoWriter+State& state, System.Int32 fieldNumber, ProtoBuf.Serializers.SerializerFeatures category, ProtoBuf.WireType wireType, T[] values, ProtoBuf.Serializers.ISerializer`1[T] serializer) [0x00009] in /_/src/protobuf-net.Core/Serializers/RepeatedSerializer.cs:493 
  at ProtoBuf.Serializers.RepeatedSerializer`2[TCollection,TItem].WriteRepeated (ProtoBuf.ProtoWriter+State& state, System.Int32 fieldNumber, ProtoBuf.Serializers.SerializerFeatures features, TCollection values, ProtoBuf.Serializers.ISerializer`1[T] serializer) [0x0009c] in /_/src/protobuf-net.Core/Serializers/RepeatedSerializer.cs:134 
  at (wrapper dynamic-method) GameNode_SaveState.proto_8(ProtoBuf.ProtoWriter/State&,GameNode_SaveState)
  at ProtoBuf.Internal.Serializers.SimpleCompiledSerializer`1[T].ProtoBuf.Serializers.ISerializer<T>.Write (ProtoBuf.ProtoWriter+State& state, T value) [0x00000] in /_/src/protobuf-net/Internal/Serializers/CompiledSerializer.cs:117 
  at ProtoBuf.ProtoWriter.WriteMessage[T] (ProtoBuf.ProtoWriter+State& state, T value, ProtoBuf.Serializers.ISerializer`1[T] serializer, ProtoBuf.PrefixStyle style, System.Boolean recursionCheck) [0x0001c] in /_/src/protobuf-net.Core/ProtoWriter.cs:258 
  at ProtoBuf.ProtoWriter+State.WriteAny[T] (System.Int32 fieldNumber, ProtoBuf.Serializers.SerializerFeatures features, T value, ProtoBuf.Serializers.ISerializer`1[T] serializer) [0x00077] in /_/src/protobuf-net.Core/ProtoWriter.State.WriteMethods.cs:377 
  at ProtoBuf.Internal.KeyValuePairSerializer`2[TKey,TValue].Write (ProtoBuf.ProtoWriter+State& state, System.Collections.Generic.KeyValuePair`2[TKey,TValue] value) [0x00040] in /_/src/protobuf-net.Core/Internal/KeyValuePairSerializer.cs:63 
  at ProtoBuf.ProtoWriter.WriteMessage[T] (ProtoBuf.ProtoWriter+State& state, T value, ProtoBuf.Serializers.ISerializer`1[T] serializer, ProtoBuf.PrefixStyle style, System.Boolean recursionCheck) [0x0001c] in /_/src/protobuf-net.Core/ProtoWriter.cs:258 
  at ProtoBuf.Serializers.MapSerializer`3[TCollection,TKey,TValue].Write[TEnumerator] (ProtoBuf.ProtoWriter+State& state, System.Int32 fieldNumber, ProtoBuf.WireType wireType, TEnumerator& enumerator, ProtoBuf.Internal.KeyValuePairSerializer`2[TKey,TValue]& pairSerializer) [0x00024] in /_/src/protobuf-net.Core/Serializers/MapSerializer.cs:88 
  at ProtoBuf.Serializers.DictionarySerializer`2[TKey,TValue].Write (ProtoBuf.ProtoWriter+State& state, System.Int32 fieldNumber, ProtoBuf.WireType wireType, System.Collections.Generic.Dictionary`2[TKey,TValue] values, ProtoBuf.Internal.KeyValuePairSerializer`2[TKey,TValue]& pairSerializer) [0x00008] in /_/src/protobuf-net.Core/Serializers/MapSerializer.cs:160 
  at ProtoBuf.Serializers.MapSerializer`3[TCollection,TKey,TValue].WriteMap (ProtoBuf.ProtoWriter+State& state, System.Int32 fieldNumber, ProtoBuf.Serializers.SerializerFeatures features, TCollection values, ProtoBuf.Serializers.SerializerFeatures keyFeatures, ProtoBuf.Serializers.SerializerFeatures valueFeatures, ProtoBuf.Serializers.ISerializer`1[T] keySerializer, ProtoBuf.Serializers.ISerializer`1[T] valueSerializer) [0x00029] in /_/src/protobuf-net.Core/Serializers/MapSerializer.cs:72 
  at (wrapper dynamic-method) SaveSlot.proto_3(ProtoBuf.ProtoWriter/State&,SaveSlot)
  at ProtoBuf.Internal.Serializers.SimpleCompiledSerializer`1[T].ProtoBuf.Serializers.ISerializer<T>.Write (ProtoBuf.ProtoWriter+State& state, T value) [0x00000] in /_/src/protobuf-net/Internal/Serializers/CompiledSerializer.cs:117 
  at ProtoBuf.ProtoWriter.WriteMessage[T] (ProtoBuf.ProtoWriter+State& state, T value, ProtoBuf.Serializers.ISerializer`1[T] serializer, ProtoBuf.PrefixStyle style, System.Boolean recursionCheck) [0x0001c] in /_/src/protobuf-net.Core/ProtoWriter.cs:258 
  at ProtoBuf.ProtoWriter+State.WriteMessage[T] (System.Int32 fieldNumber, ProtoBuf.Serializers.SerializerFeatures features, T value, ProtoBuf.Serializers.ISerializer`1[T] serializer) [0x0001c] in /_/src/protobuf-net.Core/ProtoWriter.State.WriteMethods.cs:333 
  at (wrapper dynamic-method) SaveFile.proto_1(ProtoBuf.ProtoWriter/State&,SaveFile)
  at ProtoBuf.Internal.Serializers.SimpleCompiledSerializer`1[T].ProtoBuf.Serializers.ISerializer<T>.Write (ProtoBuf.ProtoWriter+State& state, T value) [0x00000] in /_/src/protobuf-net/Internal/Serializers/CompiledSerializer.cs:117 
  at ProtoBuf.ProtoWriter+State.WriteAsRoot[T] (T value, ProtoBuf.Serializers.ISerializer`1[T] serializer) [0x00057] in /_/src/protobuf-net.Core/ProtoWriter.State.WriteMethods.cs:575 
  at ProtoBuf.ProtoWriter+State.SerializeRoot[T] (T value, ProtoBuf.Serializers.ISerializer`1[T] serializer) [0x00040] in /_/src/protobuf-net.Core/ProtoWriter.State.WriteMethods.cs:548 
  at ProtoBuf.Meta.TypeModel.SerializeImpl[T] (ProtoBuf.ProtoWriter+State& state, T value) [0x00048] in /_/src/protobuf-net.Core/Meta/TypeModel.cs:360 
  at ProtoBuf.Serializer.Serialize[T] (System.IO.Stream destination, T instance, System.Object userState) [0x0000d] in /_/src/protobuf-net/Serializer.Serialize.cs:32 
  at ProtoBuf.Serializer.Serialize[T] (System.IO.Stream destination, T instance) [0x00000] in /_/src/protobuf-net/Serializer.Serialize.cs:19 
  at SaveFileManager+<>c__DisplayClass31_0.<Save_Async>b__0 () [0x00033] in D:\PropLogic\Unity\ArcSine285\Assets\Systems_Game\GameData\SaveFileManager.cs:196 
UnityEngine.Debug:LogError (object)
SaveFileManager/<>c__DisplayClass31_0:<Save_Async>b__0 () (at Assets/Systems_Game/GameData/SaveFileManager.cs:201)
System.Threading._ThreadPoolWaitCallback:PerformWaitCallback ()

c#

serialization

deserialization

protobuf-net

0 Answers

Your Answer

Accepted video resources