Dictionary serialization broken after deleting Library folder

Issue #760 resolved
Vitaliy Shlyahovchuk created an issue
  1. In project there are one scriptable object with dictionary inside.
  2. Add to that dictionary one item.
  3. Close unity editor.
  4. Reopen unity editor, everything ok, previously created item is in dictionary.
  5. Close unity editor.
  6. Delete Library folder of unity project(simulating recreating project for cloud build unit tests)
  7. Reopen unity editor. Bug happened - there is no item in dictionary

Project for bug reproducing in attachment

Bug reproducing in different versions of unity(2019.4.21f, 2020.2.6f1) and on different versions of odin inspector(2.1.13, 3.0.4).
Deleting Library folder - it is simulating process of recreating project in cloud build for unit tests

Comments (7)

  1. Tor Esa Vestergaard

    Hello, thanks for the issue report!

    I sat down and had a long, hard look at the issue - thank you for setting up a great and reliable reproduction project and set of steps. This is the first time I have ever seen this bug reported in a way and with a setup where I can reliably reproduce it every time I try. This has let me dig deep down into the actual root issue, and I’ve determined that the error is happening on Unity’s side, though the causal chain is a little complicated to explain. I have made a detailed issue report to Unity and will be following up on it with all means at my disposal - believe me, I want this issue fixed as much as you do, we’ve been trying to nail it down for a really long time! 🙂

    I can try to explain the basics of the issue that is happening by copy pasting and paraphrasing a bit from my issue report to Unity:


    The nature of the beast

    During reimport (and maybe at other times), asset references are deserialized as the wrong type by Unity, losing polymorphism. IE, if you store a unity object reference to a "CustomType" asset in a field of type "UnityEngine.Object", then during reimport that field will be assigned an object instance of type "UnityEngine.Object" instead of "CustomType".

    Odin adds support for custom-serialized data to be stored in Unity objects. The way this is done is by using the ISerializationCallbackReceiver interface to write to and read from a series of Unity-serialized data members, acting as a "translator". One of these members is a list of type List<UnityEngine.Object>, containing the Unity objects that were referenced by the 3rd-party serialized data.

    This data loss issue happens because, during reimport, Unity is assigning empty object instances of type UnityEngine.Object to this reference list instead of object instances of the original type, likely as placeholder references for assets to be imported and deserialized properly later. When Odin then attempts to assign these references back to where they are supposed to go, it cannot be done, because they are of the wrong type. Therefore the asset reference is lost during a full project import.

    Now, sometimes Unity will remember to deserialize the asset again after reimport, when it has all the correct data prepared to be deserialized, thus fixing the issue the first time the asset is used. Your project is not one of those cases where that happens, for some reason that is unknown to me. Instead, no correction happens, and the data is simply wrong until Unity is closed and opened again without an import happening.


    Now, while we wait for Unity to fix this issue, I have some theories as to hotfixes that could help you - one hack that might work for you guys is, during your cloud build just after import but before you use any assets to do anything, to load all assets you’re seeing issues with from the AssetDatabase, and make them deserialize themselves again, now hopefully with the correct data:

    UnityEngine.Object[] theAssetsToFix = LoadTheAssetsSomehow();
    
    foreach (var asset in theAssetsToFix)
    {
        if (asset is ISerializationCallbackReceiver receiver)
        {
            receiver.OnAfterDeserialize();
        }
    }
    

    I am not certain this would help, but it is my best bet. I know that if you reimport, close the project and then open it again, then all data will have been deserialized correctly. However, I realize that is not very helpful advice for making cloud builds in particular work correctly. The key either way is that Unity must somehow be prompted to load the asset’s data from disk again to recover what was lost during the import process.

    Hopefully this helps; please feel free to contact me on Discord or by mail if you have any further questions. I will keep this issue updated with anything I learn from Unity’s side.

    Cheers!

    ( Oh, and I’ve removed your repro project file, as it included all of Odin in it. )

  2. Log in to comment