Upgraded from latest 2018 to latest 2019. Now tests fail when loading scenes

When I run all my tests, I now get this error late in the run:

Destroy may not be called from edit mode! Use DestroyImmediate instead.
Also think twice if you really want to destroy something in edit mode. Since this will destroy objects permanently.
0x00007FF69BFB93CC (Unity) StackWalker::GetCurrentCallstack
0x00007FF69BFBC881 (Unity) StackWalker::ShowCallstack
0x00007FF69A728695 (Unity) GetStacktrace
0x00007FF69C9D6C60 (Unity) DebugStringToFile
0x00007FF69BF43634 (Unity) Scripting::smile:estroyObjectFromScripting
0x00007FF69C018FE3 (Unity) Object_CUSTOM_Destroy
0x0000022420BA8F96 (Mono JIT Code) (wrapper managed-to-native) UnityEngine.Object:smile:estroy (UnityEngine.Object,single)
0x0000022420BA8E6B (Mono JIT Code) [UnityEngineObject.bindings.cs:303] UnityEngine.Object:smile:estroy (UnityEngine.Object)
0x0000022420A3616B (Mono JIT Code) [Graphic.cs:511] UnityEngine.UI.Graphic:OnDestroy ()
0x0000022416212E18 (Mono JIT Code) (wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr)
0x00007FFE0399BBCB (mono-2.0-bdwgc) [mini-runtime.c:2809] mono_jit_runtime_invoke
0x00007FFE03922252 (mono-2.0-bdwgc) [object.c:2919] do_runtime_invoke
0x00007FFE0392B25F (mono-2.0-bdwgc) [object.c:2966] mono_runtime_invoke
0x00007FF69BF4B036 (Unity) scripting_method_invoke
0x00007FF69BF45335 (Unity) ScriptingInvocation::Invoke
0x00007FF69BF455DE (Unity) ScriptingInvocation::InvokeChecked
0x00007FF69BF9FAF3 (Unity) SerializableManagedRef::CallMethod
0x00007FF69BF19966 (Unity) MonoBehaviour::WillDestroyComponent
0x00007FF69B21F1EE (Unity) GameObject::WillDestroyGameObject
0x00007FF69BA31C25 (Unity) PreDestroyRecursive
0x00007FF69BA31CE6 (Unity) PreDestroyRecursive
0x00007FF69BA31CE6 (Unity) PreDestroyRecursive
0x00007FF69BA31CE6 (Unity) PreDestroyRecursive
0x00007FF69BA31CE6 (Unity) PreDestroyRecursive
0x00007FF69BA31CE6 (Unity) PreDestroyRecursive
0x00007FF69BA31CE6 (Unity) PreDestroyRecursive
0x00007FF69BA31CE6 (Unity) PreDestroyRecursive
0x00007FF69BA31CE6 (Unity) PreDestroyRecursive
0x00007FF69BA2F3FB (Unity) DestroyObjectHighLevel_Internal
0x00007FF69BA2F21E (Unity) DestroyObjectHighLevel
0x00007FF69BA43485 (Unity) DestroyWorldObjects
0x00007FF69A20BD04 (Unity) EditorSceneManager::RestoreSceneBackups
0x00007FF69A20B558 (Unity) EditorSceneManager::OpenSceneLoaded
0x00007FF69A20A574 (Unity) EditorSceneManager::OpenScene
0x00007FF69A455213 (Unity) EditorSceneManagerBindings::OpenScene
0x00007FF69AF735FF (Unity) EditorSceneManager_CUSTOM_OpenScene_Injected
0x0000022420A2EC00 (Mono JIT Code) (wrapper managed-to-native) UnityEditor.SceneManagement.EditorSceneManager:OpenScene_Injected (string,UnityEditor.SceneManagement.OpenSceneMode,UnityEngine.SceneManagement.Scene&)
0x0000022420A2EA9B (Mono JIT Code) UnityEditor.SceneManagement.EditorSceneManager:OpenScene (string,UnityEditor.SceneManagement.OpenSceneMode)
0x0000022420A2E943 (Mono JIT Code) [EditorSceneManager.cs:32] UnityEditor.SceneManagement.EditorSceneManager:OpenScene (string)
0x0000022420A2E523 (Mono JIT Code) [TestSceneLoader.cs:10] TestSceneLoader:ReloadLevelScene ()
0x0000022420A6B0BB (Mono JIT Code) [LevelAcceptanceTests.cs:38] LevelAcceptanceTests:SetUp ()
0x000002242074AEF0 (Mono JIT Code) (wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr)
0x00007FFE0399BBCB (mono-2.0-bdwgc) [mini-runtime.c:2809] mono_jit_runtime_invoke
0x00007FFE03922252 (mono-2.0-bdwgc) [object.c:2919] do_runtime_invoke
0x00007FFE0392B432 (mono-2.0-bdwgc) [object.c:3071] mono_runtime_invoke_checked
0x00007FFE0392BBC9 (mono-2.0-bdwgc) [object.c:5262] mono_runtime_try_invoke_array
0x00007FFE0392B3C6 (mono-2.0-bdwgc) [object.c:5140] mono_runtime_invoke_array_checked
0x00007FFE038D0254 (mono-2.0-bdwgc) [icall.c:3358] ves_icall_InternalInvoke
0x0000022412DA0436 (Mono JIT Code) (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
0x0000022412D9FBBB (Mono JIT Code) System.Reflection.MonoMethod:Invoke (object,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo)
0x00000224144D183F (Mono JIT Code) System.Reflection.MethodBase:Invoke (object,object[])
0x000002242074D793 (Mono JIT Code) NUnit.Framework.Internal.Reflect:InvokeMethod (System.Reflection.MethodInfo,object,object[])
0x000002242074D2A3 (Mono JIT Code) NUnit.Framework.Internal.Reflect:InvokeMethod (System.Reflection.MethodInfo,object)
0x000002242074D14B (Mono JIT Code) NUnit.Framework.Internal.Commands.SetUpTearDownItem:RunNonAsyncMethod (System.Reflection.MethodInfo,NUnit.Framework.Internal.ITestExecutionContext)
0x000002242074CFB3 (Mono JIT Code) NUnit.Framework.Internal.Commands.SetUpTearDownItem:RunSetUpOrTearDownMethod (NUnit.Framework.Internal.ITestExecutionContext,System.Reflection.MethodInfo)
0x000002242074CB33 (Mono JIT Code) NUnit.Framework.Internal.Commands.SetUpTearDownItem:RunSetUp (NUnit.Framework.Internal.ITestExecutionContext)
0x0000022420757D8B (Mono JIT Code) [SetUpTearDownCommand.cs:25] UnityEngine.TestTools.SetUpTearDownCommand/<InvokeBefore>c__Iterator0:MoveNext ()
0x0000022420754B6E (Mono JIT Code) [BeforeAfterTestCommandBase.cs:57] UnityEngine.TestTools.BeforeAfterTestCommandBase`1/<ExecuteEnumerable>c__Iterator0<T_REF>:MoveNext ()
0x0000022420755C8A (Mono JIT Code) [BeforeAfterTestCommandBase.cs:99] UnityEngine.TestTools.BeforeAfterTestCommandBase`1/<ExecuteEnumerable>c__Iterator0<T_REF>:MoveNext ()
0x0000022420755C8A (Mono JIT Code) [BeforeAfterTestCommandBase.cs:99] UnityEngine.TestTools.BeforeAfterTestCommandBase`1/<ExecuteEnumerable>c__Iterator0<T_REF>:MoveNext ()
0x0000022420A69BDA (Mono JIT Code) [EditorEnumeratorTestWorkItem.cs:101] UnityEditor.TestTools.TestRunner.EditorEnumeratorTestWorkItem/<PerformWork>c__Iterator0:MoveNext ()
0x0000022420744559 (Mono JIT Code) [CompositeWorkItem.cs:200] UnityEngine.TestRunner.NUnitExtensions.Runner.CompositeWorkItem/<RunChildren>c__Iterator1:MoveNext ()
0x000002242073BAC9 (Mono JIT Code) [CompositeWorkItem.cs:76] UnityEngine.TestRunner.NUnitExtensions.Runner.CompositeWorkItem/<PerformWork>c__Iterator0:MoveNext ()
0x0000022420744559 (Mono JIT Code) [CompositeWorkItem.cs:200] UnityEngine.TestRunner.NUnitExtensions.Runner.CompositeWorkItem/<RunChildren>c__Iterator1:MoveNext ()
0x000002242073BAC9 (Mono JIT Code) [CompositeWorkItem.cs:76] UnityEngine.TestRunner.NUnitExtensions.Runner.CompositeWorkItem/<PerformWork>c__Iterator0:MoveNext ()
0x0000022420744559 (Mono JIT Code) [CompositeWorkItem.cs:200] UnityEngine.TestRunner.NUnitExtensions.Runner.CompositeWorkItem/<RunChildren>c__Iterator1:MoveNext ()
0x000002242073BAC9 (Mono JIT Code) [CompositeWorkItem.cs:76] UnityEngine.TestRunner.NUnitExtensions.Runner.CompositeWorkItem/<PerformWork>c__Iterator0:MoveNext ()
0x0000022420744559 (Mono JIT Code) [CompositeWorkItem.cs:200] UnityEngine.TestRunner.NUnitExtensions.Runner.CompositeWorkItem/<RunChildren>c__Iterator1:MoveNext ()
0x000002242073BAC9 (Mono JIT Code) [CompositeWorkItem.cs:76] UnityEngine.TestRunner.NUnitExtensions.Runner.CompositeWorkItem/<PerformWork>c__Iterator0:MoveNext ()
0x000002242073A4AE (Mono JIT Code) [EditModeRunner.cs:219] UnityEditor.TestTools.TestRunner.EditModeRunner:MoveNextAndUpdateYieldObject ()
0x000002242073A07B (Mono JIT Code) [EditModeRunner.cs:252] UnityEditor.TestTools.TestRunner.EditModeRunner:TestConsumer ()
0x0000022425960D07 (Mono JIT Code) (wrapper delegate-invoke) <Module>:invoke_void ()
0x0000022425960A07 (Mono JIT Code) [EditorApplication.cs:200] UnityEditor.EditorApplication:Internal_CallUpdateFunctions ()
0x000002241444D3F5 (Mono JIT Code) (wrapper runtime-invoke) object:runtime_invoke_void (object,intptr,intptr,intptr)
0x00007FFE0399BBCB (mono-2.0-bdwgc) [mini-runtime.c:2809] mono_jit_runtime_invoke
0x00007FFE03922252 (mono-2.0-bdwgc) [object.c:2919] do_runtime_invoke
0x00007FFE0392B25F (mono-2.0-bdwgc) [object.c:2966] mono_runtime_invoke
0x00007FF69BF42A31 (Unity) CallStaticMonoMethod
0x00007FF69BF42631 (Unity) CallStaticMonoMethod
0x00007FF69BF423B1 (Unity) CallStaticMonoMethod
0x00007FF69A4C74F6 (Unity) SceneTracker::Update
0x00007FF69A77399B (Unity) Application::TickTimer
0x00007FF69AA33943 (Unity) MainMessageLoop
0x00007FF69AA3D347 (Unity) WinMain
0x00007FF69D36DD8E (Unity) __scrt_common_main_seh
0x00007FFE416F4034 (KERNEL32) BaseThreadInitThunk
0x00007FFE42493691 (ntdll) RtlUserThreadStart

If I run a test that failed like this all by itself, it then passes.

You’re probably interested in this code:

0x0000022420A2E523 (Mono JIT Code) [TestSceneLoader.cs:10] TestSceneLoader:ReloadLevelScene ()
0x0000022420A6B0BB (Mono JIT Code) [LevelAcceptanceTests.cs:38] LevelAcceptanceTests:SetUp ()

Here’s what the TestSceneLoader is doing on that line:

    public static void ReloadLevelScene()
    {
        var scene = EditorSceneManager.GetSceneByPath("Assets/Scenes/Level.unity");
        EditorSceneManager.OpenScene("Assets/Scenes/Level.unity");
    }

It’s important to note that these are Edit Mode tests. That Setup is run like 10+ times before this error happens. It always seems to happen on the same tests too, but if I run any of them individually, the tests pass.

Here’s my guess: Unity is now better at cleaning up after itself. Now, it’s running Destroy on objects that I left behind, but it’s calling the wrong destroy, so I get this error.

Anyway, any help would be appreciated. I’m going to delete my Library directory to see if it fixes this, because it seems to always solve half the bugs I run into with Unity.

OK, I’ve done a little more research, and discovered that if a test has this TestUtils.CallInitialization(GameObject.Find("StatsRenderer")); in it, the NEXT test will fail with the error above. If I comment out that line, this does not happen.

That line is calling Awake, OnEnable, and Start respectively on my StatsRenderer. It’s using reflection to do so.

Here’s how my StatsRenderer looks:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
using CollectionUtils;
using TMPro;

public class StatsRenderer : MonoBehaviour
{
    public LevelData levelData;
    public Transform informationPanel;
    public GameObject needsFulfilledTextTemplate;
    public GameObject levelRewardsGameObject;
    private LevelRewardCalculator levelRewardCalculator;
    private Dictionary<string, CharacterData> rewardNameToData = new Dictionary<string, CharacterData>();
    void Start()
    {
        foreach (var characterData in ScriptableObjectLoader.LoadAllCharacterData())
        {
            rewardNameToData.Add(characterData.skillPointName, characterData);
        }

        levelRewardCalculator = new LevelRewardCalculator();
        foreach (var characterStat in levelData.GetCharacterStats())
        {
            GameObject textGameObject = Instantiate(needsFulfilledTextTemplate, informationPanel);
            textGameObject.name = characterStat.characterName + "NeedsFulfilledText";
        
            textGameObject.GetComponent<TextMeshProUGUI>().text = $"{characterStat.characterName}'s Needs Fulfilled: {characterStat.successfulCount}/{characterStat.totalCount}";
        }

        foreach (var characterStat in levelData.GetCharacterStats())
        {
            if (characterStat.levelsGained > 0)
            {
                GameObject textGameObject = Instantiate(needsFulfilledTextTemplate, informationPanel);
                textGameObject.name = characterStat.characterName + "LevelUpText";

                string level = characterStat.levelsGained > 1 ? $"{characterStat.levelsGained} levels" : "a level";
                textGameObject.GetComponent<TextMeshProUGUI>().text = $"{characterStat.characterName} gained {level}!";

            }
        }
        Dictionary<string, int> levelRewards = levelRewardCalculator.CalculateLevelRewards(levelData, Repository.instance.repositoryData.gameStats);
        foreach (var entry in levelRewards)
        {
            if (entry.Value > 0 && entry.Key != "Money")
            {
                AddReward(entry.Key, entry.Value);
            }
        }
        if (levelRewards["Money"] > 0)
        {
            GameObject rewardGameObjectTemplate = Resources.Load<GameObject>("MoneyReward");
            var rewardGameObject = Instantiate(rewardGameObjectTemplate, levelRewardsGameObject.transform);
            rewardGameObject.name = "MoneyReward";
            rewardGameObject.transform.Find("Text").GetComponent<TextMeshProUGUI>().text = "+" + levelRewards["Money"] + " Money";
        }
        levelRewardsGameObject.transform.SetAsLastSibling();
    }

    private void AddReward(string rewardName, int rewardValue)
    {
        GameObject rewardGameObjectTemplate = Resources.Load<GameObject>("SkillPointReward");
        if (rewardGameObjectTemplate == null)
        {
            throw new System.NullReferenceException("Could not load a prefab named " + "SkillPointReward");
        }
        var rewardGameObject = Instantiate(rewardGameObjectTemplate, levelRewardsGameObject.transform);
        rewardGameObject.name = rewardName + "Reward";
        rewardGameObject.transform.Find("Text").GetComponent<TextMeshProUGUI>().text = "+" + rewardValue + " " + rewardName;
        try
        {
            rewardGameObject.transform.Find("Background").Find("Image").GetComponent<Image>().sprite = rewardNameToData[rewardName].skillPointImage;
            rewardGameObject.transform.Find("Background").Find("Image").GetComponent<Image>().color = rewardNameToData[rewardName].skillPointTint;
        }
        catch (KeyNotFoundException e)
        {
            throw new KeyNotFoundException($"Was looking for {rewardName} in {rewardNameToData.PrettyToString()}", e);
        }
    }

}

Still looking into this. I have a feeling I can find the exact line causing the problem by commenting out parts of this.

The error only happens if I call AddReward(entry.Key, entry.Value);

OK, I have no idea why, but for whatever reason, this single line is the cause of the problems:

rewardGameObject.transform.Find("Background").Find("Image").GetComponent<Image>().sprite = rewardNameToData[rewardName].skillPointImage;

The very similar line the occurs after it is not:

rewardGameObject.transform.Find("Background").Find("Image").GetComponent<Image>().color = rewardNameToData[rewardName].skillPointTint;

It’s not obvious to me why in 2018, the first line would be fine and in 2019 it causes an error when you try to reload the scene. Anyone else know?

If I do this line instead, the error does not happen:

rewardGameObject.transform.Find("Background").Find("Image").GetComponent<Image>().sprite = null;

OK i’ve confirmed this happens from the scene closing, not from my code. Something in Unity is trying to destroy my object using Destroy instead of DestroyImmediate. I think there’s a chance this could be a Unity bug because it seems like Unity doesn’t understand it’s in edit mode, and is trying to use Destroy to clean up instead of DestroyImmediate.

did u try using different unity versions to see if it gives different results?
also, are you running it on a local machine, or on some sort of build server ?

Can you give an example? It already works fine on the latest 2018. There’s only one 2019, so I think I’ve tried it on everything possible.

Local.

I’m experiencing the same error (“Destroy may not be called from edit mode! Use DestroyImmediate instead.”) when messing with sprites in editor.

I get this error from one of my code-generated Canvas/Image/Sprite object that’s with HideFlags.DontSave on it. When the test wants to destroy this object it cause the error. (case : https://fogbugz.unity3d.com/default.asp?1157422_sfvtcfi1jmvc3702)