RUNTIME EXCEPTION • SCRIPTING

MISSINGREFERENCEEXCEPTION: OBJECT HAS BEEN DESTROYED

The object of type 'GameObject' (or 'Transform') has been destroyed but you are still trying to access it.

What Is the Error?

Unlike a NullReferenceException (where a variable was never assigned anything in the first place), a MissingReferenceException occurs when a variable did point to a valid GameObject or Component, but that object was subsequently destroyed (via Destroy(gameObject) or a scene change) while another script continues trying to read its position, call its methods, or trigger its delegates.

Why Does It Happen?

  • Lingering Event Listeners: An object subscribed to a static C# event, was destroyed, but forgot to unsubscribe in OnDisable().
  • Follow Camera Targeting Destroyed Player: A follow camera or missile homing script reads target.position after the target aircraft has blown up and been destroyed.
  • Coroutines Running on Dead Objects: A coroutine or Invoke() continues executing after the target has been removed from the scene.

Quick Fix

💡 Unity's Custom Null Check

In Unity, destroyed objects evaluate to null when checked with if (target == null) because Unity overrides the == operator for UnityEngine.Object. Always check if the reference is valid before reading properties:

// ❌ BAD: Throws MissingReferenceException if target was destroyed!
void Update()
{
    transform.LookAt(target.position);
}

// ✅ CORRECT: Safe check accounts for destroyed Unity objects
void Update()
{
    if (target != null)
    {
        transform.LookAt(target.position);
    }
}

Step-by-Step Fix: Unsubscribing Event Listeners

The most frequent cause in production games is event delegates. Always pair event subscriptions in OnEnable() and OnDisable():

public class HealthBarUI : MonoBehaviour
{
    private void OnEnable()
    {
        PlayerCombat.OnHealthChanged += UpdateHealthBar;
    }

    private void OnDisable()
    {
        // ✅ CRITICAL: Unsubscribes before GameObject is destroyed or scene unloads!
        PlayerCombat.OnHealthChanged -= UpdateHealthBar;
    }

    private void UpdateHealthBar(float health, float max)
    {
        // UI updates here safely
    }
}

Related Guides & Tools

Frequently Asked Questions

The C# null-conditional operator (?.) bypasses Unity's custom == operator overload and checks pure CLR memory. Because Unity keeps a fake C# wrapper alive after the C++ native object is destroyed, target?.position thinks the object is not null and crashes into the dead native pointer. Always use explicit if (target != null) for UnityEngine.Object types!