Runtime exceptions
MissingReferenceException: The object of type 'X' has been destroyed but you are still trying to access it.
The exact message
MissingReferenceException: The object of type 'X' has been destroyed but you are still trying to access it.Variants of this message
- has been destroyed but you are still trying to access it
- MissingReferenceException: The object of type 'GameObject' 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.
- MissingReferenceException: The object of type 'Animator' 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.
What it means
You are holding a reference to a Unity object that has been destroyed. The C# reference still exists, but the native engine object behind it is gone, so any attempt to read or write its members fails. Unity distinguishes this from an ordinary null reference deliberately: the wording tells you the object was real at some point, which points at a lifetime problem rather than a missing assignment.
Causes and fixes
Ranked by how often they actually occur, most common first.
A cached reference outlived the object it pointed at
Storing a component or GameObject in a field and using it on later frames is normal and correct, right up until something destroys the target. The reference is not cleared for you. Enemy references held by a targeting system, and UI elements held by a controller, are the usual cases.
The fix: Test the reference before use. Comparing a UnityEngine.Object to null returns true once it has been destroyed, so a plain null check is the correct guard here even though the C# reference is not really null.
The null check works because Unity overloads == for UnityEngine.Object.
using UnityEngine; public class Turret : MonoBehaviour { private Transform target; void Update() { // True once the target has been destroyed, even though the C# // reference is not literally null. if (target == null) { target = AcquireTarget(); if (target == null) return; } transform.LookAt(target); } private Transform AcquireTarget() => null; }Source: Unity Discussions: MissingReferenceException on a destroyed Animator
Work continued after Destroy was called
Destroy does not remove the object immediately. Unity defers the actual destruction until after the current Update loop, so code running later in the same frame still sees the object, and code running on the next frame does not. A coroutine, an invoked method or a queued callback started before the destruction will therefore throw when it resumes.
The fix: Return immediately after calling Destroy on the object you are working with. For deferred work, use DestroyImmediate only in Editor tooling, and otherwise cancel the pending work: stop the coroutine, unsubscribe the event, or check the reference again after any yield.
A yield is a gap in which anything can be destroyed, including this component's own GameObject.
using System.Collections; using UnityEngine; public class Pickup : MonoBehaviour { private IEnumerator CollectRoutine(Transform collector) { yield return new WaitForSeconds(0.5f); // The collector may have been destroyed during that half second. if (collector == null) yield break; collector.GetComponent<Inventory>()?.Add(this); Destroy(gameObject); // Nothing after a Destroy of this object should touch it. } } public class Inventory : MonoBehaviour { public void Add(Pickup pickup) { } }Source: Unity Scripting API: Object.Destroy, Unity Issue Tracker: MissingReferenceException when calling Destroy from a UI Button
A scene load destroyed the object the reference pointed at
Loading a scene in Single mode destroys everything in the previous scene. A manager marked DontDestroyOnLoad survives, but the references it holds to objects from the old scene do not. This is why the error so often appears the moment a game restarts or returns from a menu, on a script that worked perfectly until then.
The fix: Re-acquire scene-owned references after each load rather than holding them across one. SceneManager.sceneLoaded is the hook for this, and clearing stale references at that point is more reliable than checking each one at the point of use.
Persistent objects must treat every scene load as invalidating what they hold.
using UnityEngine; using UnityEngine.SceneManagement; public class GameManager : MonoBehaviour { private Transform player; void OnEnable() => SceneManager.sceneLoaded += HandleSceneLoaded; void OnDisable() => SceneManager.sceneLoaded -= HandleSceneLoaded; private void HandleSceneLoaded(Scene scene, LoadSceneMode mode) { // Anything from the previous scene is gone. Re-acquire rather than // trusting what was cached before the load. player = GameObject.FindWithTag("Player")?.transform; } }Source: Unity Discussions: MissingReferenceException after LoadScene on restart, Unity Scripting API: SceneManager.sceneLoaded
An event or callback still holds the destroyed object
Subscribing to a C# event or a UnityEvent creates a reference from the publisher to the subscriber. Destroying the subscriber does not remove that subscription, so the next invocation calls into a destroyed object. UI Button onClick listeners and static events are the usual sources, and static events are the worst because they persist across scene loads.
The fix: Unsubscribe in OnDisable or OnDestroy, pairing every subscription with exactly one removal. Subscribing in OnEnable and removing in OnDisable keeps the two symmetrical and survives objects being disabled and re-enabled.
Source: Unity Discussions: MissingReferenceException from a UI dropdown callback
How to prevent it
Treat every yield, await and callback boundary as a point where anything might have been destroyed. Re-check references after resuming rather than assuming the world is as you left it.
Pair subscriptions with removals in OnEnable and OnDisable. This single habit removes most dangling-reference errors, and it costs nothing.
Prefer object pooling to repeated Instantiate and Destroy for anything created frequently. A pooled object is deactivated rather than destroyed, so references to it stay valid and the error cannot arise.
Do not use DontDestroyOnLoad as a way to keep references alive across scenes. It keeps the manager alive, not the things it points at, and the resulting stale references are harder to trace than re-acquiring cleanly on load.
Unity version differences
The message and the underlying behaviour are unchanged across supported Unity versions. Unity has discussed deprecating the == null overload for UnityEngine.Object, which would change how destroyed objects compare, but as of Unity 6 the overload is still in place and a null check remains the correct guard.
Related errors
- NullReferenceExceptionWhy Unity throws NullReferenceException, how to read the stack trace to find the exact line, and the five causes that account for nearly all of them.
- UnassignedReferenceExceptionWhy Unity says a variable has not been assigned, including the case where you did assign it, and how prefabs and scene references cause it.
- Coroutine couldn't be startedWhy Unity refuses to start a coroutine on an inactive GameObject, including the case where the object looks active, and what to use instead.
Related tools
- Scripting OrderInteractive Unity MonoBehaviour lifecycle diagram. When does Awake, Start, Update, and every callback run.
- Object Pool GeneratorGenerate production-ready Unity object pooling code with configurable options.
- Coroutine vs AsyncSide-by-side comparison of Unity coroutines and async/await with code for every common pattern.
Sources
- Unity Scripting API: Object.Destroy
- Unity Scripting API: Object.DontDestroyOnLoad
- Unity Discussions: MissingReferenceException on a destroyed Animator
- Unity Issue Tracker: MissingReferenceException when calling Destroy from a UI Button
- Unity Discussions: MissingReferenceException after LoadScene on restart
- Unity Scripting API: SceneManager.sceneLoaded
- Unity Discussions: MissingReferenceException from a UI dropdown callback