Game Dev Cheat Sheet

Runtime exceptions

Coroutine couldn't be started because the game object 'X' is inactive!

The exact message

Coroutine couldn't be started because the game object 'X' is inactive!
Variants of this message
  • Coroutine couldn't be started because the game object is inactive
  • Coroutine couldn't be started because the the game object is inactive!
  • Coroutine couldn't be started because the game object 'Scene Loader' is inactive

What it means

StartCoroutine was called on a MonoBehaviour whose GameObject is inactive. Coroutines are driven by the object that owns them, so an inactive object has nothing to advance them and Unity refuses to start one rather than creating a coroutine that would never run. Note that the message quotes the object's name, which is the quickest way to find out which one it is.

Causes and fixes

Ranked by how often they actually occur, most common first.

  1. The object was deactivated before the coroutine was started

    A common sequence is to hide something with SetActive(false) and then start a coroutine on it to handle a fade, a delay or a cleanup step. By that point the object cannot run anything. The same happens when a coroutine is started on a UI panel that begins the scene deactivated.

    The fix: Start the coroutine before deactivating, or run it on an object that stays active. A manager that is always enabled is the usual home for work that has to outlive the object it concerns.

    Order matters: the coroutine must be started while the object can still run it.

    using System.Collections;
    using UnityEngine;
    
    public class Panel : MonoBehaviour
    {
        // Wrong: nothing can advance the coroutine once the object is inactive.
        public void HideBroken()
        {
            gameObject.SetActive(false);
            StartCoroutine(FadeOut());
        }
    
        // Right: fade first, then deactivate at the end of the routine.
        public void Hide()
        {
            StartCoroutine(FadeThenHide());
        }
    
        private IEnumerator FadeThenHide()
        {
            yield return FadeOut();
            gameObject.SetActive(false);
        }
    
        private IEnumerator FadeOut()
        {
            yield return new WaitForSeconds(0.25f);
        }
    }

    Source: Unity Discussions: coroutine couldn't be started because the game object is inactive

  2. A parent is inactive, so the object is inactive too

    An object is only active in the scene if it and every ancestor above it are active. Selecting the object and seeing its own checkbox ticked proves nothing if a parent higher up is disabled. This is the version that reads as a contradiction, because the object plainly looks enabled in the Inspector.

    The fix: Check activeInHierarchy rather than activeSelf. activeSelf reports only the object's own checkbox; activeInHierarchy accounts for every parent and is what determines whether a coroutine can run.

    The two properties answer different questions, and only one of them matters here.

    using UnityEngine;
    
    public class Diagnostics : MonoBehaviour
    {
        void Start()
        {
            // True if this object's own checkbox is ticked.
            Debug.Log($"activeSelf: {gameObject.activeSelf}");
    
            // True only if this object and every parent are active.
            // This is the one StartCoroutine cares about.
            Debug.Log($"activeInHierarchy: {gameObject.activeInHierarchy}");
    
            if (!gameObject.activeInHierarchy)
            {
                Debug.LogWarning($"{name} cannot run coroutines: a parent is inactive.", this);
            }
        }
    }

    Source: Unity Scripting API: GameObject.activeInHierarchy, Unity Discussions: error appears when the GameObject looks active

  3. A scene transition deactivated the object mid-sequence

    Loading a scene tears down the previous one, and objects can be deactivated or destroyed between a coroutine being requested and it actually starting. A loading screen that starts a coroutine on an object belonging to the outgoing scene is the classic case, which is why this error clusters around scene transitions.

    The fix: Run transition work on an object that survives the load, marked with DontDestroyOnLoad, or on a manager belonging to the incoming scene. Re-check the object is still active after any await or yield that spans a load.

    Source: Unity Scripting API: Object.DontDestroyOnLoad, GameDev.tv: error when transitioning to a new scene

  4. The object was deactivated between the check and the call

    Checking activeInHierarchy and then calling StartCoroutine leaves a window in which something else can deactivate the object, usually another script responding to the same event. The check passes, the call fails, and the code looks correct on inspection. This is rare but genuinely happens during rapid transitions.

    The fix: Move the work to an object whose lifetime you control rather than defending the call site. Where that is not practical, wrapping the call and tolerating the failure is honest, but it is a symptom of ownership being in the wrong place.

How to prevent it

Put long-running or transition work on a persistent manager rather than on the objects it affects. An object that hides, dies or unloads partway through is the wrong owner for a routine that has to finish.

Order deactivation last. Anything that needs to run before an object disappears must be started while it is still active, and the deactivation belongs at the end of that routine rather than before it.

Use activeInHierarchy when you need to know whether something can actually run. activeSelf answers a different question and is the reason this error so often looks impossible.

Consider async and await with a CancellationToken where work must survive an object being disabled. Unlike coroutines, that work is not owned by a MonoBehaviour, which is sometimes exactly what you want and sometimes a leak waiting to happen.

Unity version differences

Behaviour is unchanged across supported versions. Older Unity releases emitted the message with a duplicated word, as "because the the game object is inactive", which is worth knowing when searching for it.

Sources

Frequently asked questions

The GameObject is active in the Inspector, so why do I get this error?
Because a parent is inactive. An object only counts as active if every ancestor above it is active as well, and the Inspector checkbox shows only the object's own state. Log gameObject.activeInHierarchy rather than activeSelf, and walk up the Hierarchy looking for the disabled parent.
What is the difference between activeSelf and activeInHierarchy?
activeSelf is the object's own checkbox in the Inspector, unaffected by its parents. activeInHierarchy is whether the object is actually active in the scene, which requires the object and every ancestor to be active. Coroutines, Update and most other behaviour depend on activeInHierarchy.
Does disabling a component stop its coroutines?
No, and this catches people out. Setting enabled to false on a MonoBehaviour stops Update but lets its coroutines continue. Deactivating the GameObject does stop them, and they do not resume when it is reactivated. If you need a coroutine to stop with the component, stop it explicitly in OnDisable.
Can I run a coroutine on an inactive object at all?
Not on the inactive object itself. Start it on a different MonoBehaviour that is active, since the coroutine is driven by whichever object you call StartCoroutine on rather than by whatever it operates on. A persistent manager is the usual choice, and async and await is the alternative when the work should not be tied to an object's lifetime at all.
Do coroutines resume when the object is reactivated?
No. Deactivating a GameObject stops its coroutines permanently, and reactivating it does not restart them. Any routine that needs to continue has to be started again, which is worth remembering for objects that are pooled and reused rather than destroyed.

Last updated: