MissingReferenceException thrown under certain circumstances when using UnityEngine.Object as dictionary keys

Issue #413 resolved
Fausto Cheder created an issue
  • Have a dictionary with keys of UnityEngine.Object

  • open it in new inspector and lock the inspector

  • using another inspector, drag a UnityEngine.Object and add it to the dictionary

  • while still watching the first inspector (with the dictionary), delete the UnityEngine.Object

  • notice that dictionary drawer will be broken and exceptions will be thrown

Full stack trace + code parts is below

[Exception] MissingReferenceException: The object of type 'TestBehavior' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
Rethrow as OdinPropertyException: This error occurred while being drawn by Odin.
Odin Property Path: Data
Odin Drawer Chain:
> PropertyContextMenuDrawer<Dictionary<Object, fiDropdownGraphMetadataSerializer>>
> ReferenceDrawer<Dictionary<Object, fiDropdownGraphMetadataSerializer>>
> FixUnityNullDrawer<Dictionary<Object, fiDropdownGraphMetadataSerializer>>
> NonSerializedShowInInspectorWarningAttributeDrawer
> LabelTextAttributeDrawer
> ReferencePathConflictDrawer<Dictionary<Object, fiDropdownGraphMetadataSerializer>>
> ReferenceValueConflictDrawer<Dictionary<Object, fiDropdownGraphMetadataSerializer>>
> NullableReferenceDrawer<Dictionary<Object, fiDropdownGraphMetadataSerializer>>
> DictionaryDrawer<Dictionary<Object, fiDropdownGraphMetadataSerializer>, Object, fiDropdownGraphMetadataSerializer>
> CollectionDrawer<Dictionary<Object, fiDropdownGraphMetadataSerializer>>
> CompositeDrawer.
Object.get_name()    C:/buildslave/unity/build/Runtime/Export/UnityEngineObject.bindings.cs:198
196:   var obj = Internal_CloneSingle(original);
-->198:   if (obj == null)
199:       throw new UnityException(cloneDestroyedMessage);

Sirenix.Serialization.DictionaryKeyUtility+UnityObjectKeyComparer`1[T].Compare()    F:/Sirenix/OdinSerializer/OdinSerializer/Utilities/Extensions/FieldInfoExtensions.cs:38
36:   {
37:       while (aliasFieldInfo.AliasedField is MemberAliasFieldInfo)
-->38:       {
39:           aliasFieldInfo = aliasFieldInfo.AliasedField as MemberAliasFieldInfo;
40:       }

Sirenix.Serialization.DictionaryKeyUtility+KeyComparer`1[T].Compare()    F:/Sirenix/OdinSerializer/OdinSerializer/Utilities/Extensions/GarbageFreeIterators.cs:57
55:   /// </summary>
56:   public ListIterator(List<T> list)
-->57:   {
58:       this.isNull = list == null;
59:       if (this.isNull)

Sirenix.OdinInspector.Editor.StrongDictionaryPropertyResolver`3[TDictionary,TKey,TValue].Update()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Value Entries/UnityPropertyGetterSetter.cs:65
64:   public object GetValue(object owner)
-->65:   {
66:       TOwner castOwner = (TOwner)owner;
67:       return this.GetValue(ref castOwner);

Sirenix.OdinInspector.Editor.StrongDictionaryPropertyResolver`3[TDictionary,TKey,TValue].EnsureUpdated()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Value Entries/UnityPropertyGetterSetter.cs:47
45:   public TValue GetValue(ref TOwner owner)
46:   {
-->47:       if (ValueGetter == null || ValueSetter == null)
48:       {
49:           Debug.LogError("Can't get a value of type " + typeof(TValue).GetNiceName() + " directly from a Unity property.");

Sirenix.OdinInspector.Editor.StrongDictionaryPropertyResolver`3[TDictionary,TKey,TValue].GetChildInfo()

Sirenix.OdinInspector.Editor.BaseKeyValueMapResolver`1[TMap].ChildPropertyRequiresRefresh()

PropertyChildren.NeedsRefresh()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Misc/Type Search/TypeSearchIndex.cs:417
416:   var array = CachedTargetArray1;
-->417:   array[0] = target;
419:   if (!this.resultCache.TryGetValue(array, out result))

PropertyChildren.Get()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Misc/Type Search/TypeSearchIndex.cs:221
220:   TypeSearchResult[] fastResultArray;
222:   // The following merge signature-based caching logic results in a roughly 2-3x speedup over doing the actual merge, once the actual merge has been done once
223:   var mergeSignature = new MergeSignature(results);

PropertyChildren.get_Item()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Misc/Type Search/TypeMatchIndexingRule.cs:24
22:   }
-->24:   public bool Process(ref TypeSearchInfo info, ref string errorMessage)
25:   {
26:       return this.rule(ref info, ref errorMessage);

Sirenix.OdinInspector.Editor.Drawers.DictionaryDrawer`3[TDictionary,TKey,TValue].DrawElements()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Misc/SerializedPropertyUtilities.cs:22
20:   public static class SerializedPropertyUtilities
21:   {
-->22:       private static Dictionary<Type, Delegate> PrimitiveValueGetters = new Dictionary<Type, Delegate>()
23:       {
24:           { typeof(int),              (Func<SerializedProperty, int>)             (p => p.intValue) },

Sirenix.OdinInspector.Editor.Drawers.DictionaryDrawer`3[TDictionary,TKey,TValue].DrawPropertyLayout()    <960f176f755e4902a256b606dc25c96b>:0

OdinDrawer.CallNextDrawer()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Windows/SerializationDebugger/MemberSerializationInfo.cs:32
30:   }
-->32:   public static bool HasAny(this SerializationBackendFlags e, SerializationBackendFlags flags)
33:   {
34:       return (e & flags) != 0;

Sirenix.OdinInspector.Editor.Drawers.NullableReferenceDrawer`1[T].DrawPropertyLayout()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Value Drawers/QuaternionDrawer.cs:62
60:   genericMenu.AddItem(new GUIContent("Right", "Set the axis to (1, 0, 0)"), axis == Vector3.right && angle != 0f, () => SetAxis(property, Vector3.right));
61:   genericMenu.AddItem(new GUIContent("Left", "Set the axis to (-1, 0, 0)"), axis == Vector3.left, () => SetAxis(property, Vector3.left));
-->62:   genericMenu.AddItem(new GUIContent("Up", "Set the axis to (0, 1, 0)"), axis == Vector3.up, () => SetAxis(property, Vector3.up));
63:   genericMenu.AddItem(new GUIContent("Down", "Set the axis to (0, -1, 0)"), axis == Vector3.down, () => SetAxis(property, Vector3.down));
64:   genericMenu.AddItem(new GUIContent("Forward", "Set the axis property to (0, 0, 1)"), axis == Vector3.forward, () => SetAxis(property, Vector3.forward));

OdinDrawer.CallNextDrawer()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Windows/SerializationDebugger/MemberSerializationInfo.cs:32
30:   }
-->32:   public static bool HasAny(this SerializationBackendFlags e, SerializationBackendFlags flags)
33:   {
34:       return (e & flags) != 0;

Sirenix.OdinInspector.Editor.Drawers.ReferenceValueConflictDrawer`1[T].DrawPropertyLayout()    <960f176f755e4902a256b606dc25c96b>:0

OdinDrawer.CallNextDrawer()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Windows/SerializationDebugger/MemberSerializationInfo.cs:32
30:   }
-->32:   public static bool HasAny(this SerializationBackendFlags e, SerializationBackendFlags flags)
33:   {
34:       return (e & flags) != 0;

Sirenix.OdinInspector.Editor.Drawers.ReferencePathConflictDrawer`1[T].DrawPropertyLayout()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Attribute Drawers/ValueDropdownAttributeDrawer.cs:64
62:   this.getValues = () =>
63:   {
-->64:       return (this.rawGetter.GetValue() as IEnumerable)
65:           .Cast<object>()
66:           .Where(x => x != null)

OdinDrawer.CallNextDrawer()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Windows/SerializationDebugger/MemberSerializationInfo.cs:32
30:   }
-->32:   public static bool HasAny(this SerializationBackendFlags e, SerializationBackendFlags flags)
33:   {
34:       return (e & flags) != 0;

LabelTextAttributeDrawer.DrawPropertyLayout()    <960f176f755e4902a256b606dc25c96b>:0

OdinDrawer.CallNextDrawer()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Windows/SerializationDebugger/MemberSerializationInfo.cs:32
30:   }
-->32:   public static bool HasAny(this SerializationBackendFlags e, SerializationBackendFlags flags)
33:   {
34:       return (e & flags) != 0;

Sirenix.OdinInspector.Editor.Drawers.FixUnityNullDrawer`1[T].DrawPropertyLayout()    <960f176f755e4902a256b606dc25c96b>:0

OdinDrawer.CallNextDrawer()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Windows/SerializationDebugger/MemberSerializationInfo.cs:32
30:   }
-->32:   public static bool HasAny(this SerializationBackendFlags e, SerializationBackendFlags flags)
33:   {
34:       return (e & flags) != 0;

Sirenix.OdinInspector.Editor.Drawers.ReferenceDrawer`1[T].DrawPropertyLayout()    <960f176f755e4902a256b606dc25c96b>:0

OdinDrawer.CallNextDrawer()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Windows/SerializationDebugger/MemberSerializationInfo.cs:32
30:   }
-->32:   public static bool HasAny(this SerializationBackendFlags e, SerializationBackendFlags flags)
33:   {
34:       return (e & flags) != 0;

Sirenix.OdinInspector.Editor.Drawers.PropertyContextMenuDrawer`1[T].DrawPropertyLayout()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Attribute Drawers/OnValueChangedAttributeDrawer.cs:83
81:   if (parameters.Length == 0)
82:   {
-->83:       action = (int index) =>
84:       {
85:           object inst = entry.Property.ParentValues[index];

OdinDrawer.DrawProperty()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:368
366:   [EnableIf("EnableCaching")]
367:   public void DeleteCache()
-->368:   {
369:       this.approximateSizePerEntry = defaultApproximateSizePerEntry;
370:       this.cache.Clear();

InspectorProperty.Draw()    <960f176f755e4902a256b606dc25c96b>:0

DebugLogHandler.LogException()

LALogHandler.LogException()    Assets/Aftertile/Modules/Debug/Internal/LALogHandler.cs:82
80:       }
-->82:       _originalLogException(exception, context);
83:   }

Debug.LogException()

InspectorProperty.Draw()

InspectorUtilities.DrawPropertiesInTree()    F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Windows/SerializationDebugger/SerializationInfoMenuItem.cs:27
25:   {
26:       if (Event.current.type == EventType.Repaint)
-->27:       {
28:           {
29:               labelRect.width -= 10;

PropertyTree.Draw()

OdinEditor.DrawTree()

OdinEditor.DrawOdinInspector()

OdinEditor.OnInspectorGUI()

GUIUtility.ProcessEvent()

Comments (3)

  1. Tor Esa Vestergaard

    This issue has been resolved - you know where to find me if you want the fix before it comes out in a patch :)

  2. Log in to comment