Unity throws error trying to destroy transform on application quit

I have some operations that I need to do when an object gets inactive, and they work ok in general cases, except when I exit play mode (application quits).
When I exit play mode, if the object is active, it will throw errors about destroying some transforms, like this:

Can't destroy Transform component (...)

This is the code I have in OnDisable, which unparents a child object from this object:

private void OnDisable()
    {
        for (int i = 0; i < mSpinningFlames.Count; ++i)
        {
            if (mSpinningFlames[i] != null)
            {
                mSpinningFlames[i].transform.parent = null;
            }
        }

        mSpinningFlames.Clear();
        mFlamesEnded.Clear();
    }

What’s causing this? Is there any workaround?

As it says you cannot destroy a transform. You can only destroy gameobjects. So what you most likely want to do is, is just add .gameObject to the transform you are trying to destroy. So if what you do now is Destroy(someTransform), then what you should be doing is Destroy(someTransform.gameObject).

But i dont think the code you posted is what’s actually triggering this error, as you are not actually destroying anything.

Are you sure you even have to do these things on application quit? For what reason?

This is actually the code that triggers it, it’s super checked. And as you see I’m not destroying anything. And the code is not destroying any gameobject anywhere, so the error must be something Unity does when exiting play mode.
And no, I don’t necessarily need to do those operation on quit, just when the gameobject gets disabled. But when the app quits, the OnDisable functions get called, so that’s why that is called and the unparenting triggers the destroying error for some reason

When a Unity application quits, Unity destroys all game objects, and when an object is destroyed, its OnDisable function gets called. This can cause a variety of weird problems due to the fact that other game objects that would normally exist might have already been destroyed by the time it gets around to calling functions on your particular object.

I constantly run into this problem with deregistering listeners. You’d think you could just write something like:

void OnEnable()
{
    Singleton.Instance.SomeEvent += MyListener;
}
void OnDisable()
{
    Singleton.Instance.SomeEvent -= MyListener;
}

…but this will sometimes cause errors when the app is quitting, because the Singleton got destroyed before this particular object did. So instead, I have to do something like:

private bool quitting = false;
void OnApplicationQuit()
{
    quitting = true;
}

void OnEnable()
{
    Singleton.Instance.SomeEvent += MyListener;
}
void OnDisable()
{
    if (!quitting) Singleton.Instance.SomeEvent -= MyListener;
}

Your error message is pretty confusing in relation to your code, but my guess is that the root cause is the same, and you could probably use the same workaround I do (above).

(My best guess regarding your actual error is that Unity’s implementation of the setter on the Transform.parent property assumes that the current parent has not been destroyed, and misbehaves in some way if it has.)

I think it would have been smarter if Unity did not call OnDestroy and OnDisable on all objects when quitting, on the assumption that almost anything you’d put in those functions would be irrelevant if the app is quitting anyway, and instead required objects that do need to do something during quit to implement OnApplicationQuit. But that would be a breaking change for existing apps built under the current system, so we’re probably stuck with the current version forever.

2 Likes

I was absolutely unaware of this problem, and i agree that it’s annoying. There is probably a good reason to call OnDestroy when quitting. I believe i even used it in some burst class to prevent an exception from occuring - but that’s more of a convenience in editor mode which wouldnt really affect a released game. It may also allow of “on quit saving” or similar approaches, even tho i dont think using OnDestroy for something like that would be the best approach.

You got me thinking tho, if Unity even has a way to adjust the order of execution for different Update() functions that rely on each other, then it probably should also include a way to adjust the order of destruction to adress problems like you described above.

I assumed it has something to do with that, Unity callind OnDisable after the objects get destroyed, but I didn’t know that OnApplicationQuit() is called before OnDisable() so that’s a good workaround! Thanks!