Game Dev Cheat Sheet

Runtime exceptions

UnassignedReferenceException: The variable 'X' of 'Y' has not been assigned.

The exact message

UnassignedReferenceException: The variable 'X' of 'Y' has not been assigned.
Variants of this message
  • UnassignedReferenceException
  • has not been assigned.
  • You probably need to assign the variable in the inspector.
  • You probably need to assign the 'X' variable of the 'Y' script in the inspector.

What it means

A serialised field that Unity expected you to fill in the Inspector is empty. Unity throws this rather than a plain NullReferenceException because it can see the field was meant to be assigned in the editor, and the message names both the variable and the script so you can go straight to it. The interesting cases are the ones where you are certain you did assign it, which almost always come down to assigning it on the wrong object.

Causes and fixes

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

  1. The field is genuinely empty in the Inspector

    The straightforward case, and the one the message describes. A public or [SerializeField] field shows as None in the Inspector until something is dragged into it. Adding a new field to a script that is already used in several places is the usual trigger, because existing objects keep their saved data and the new field starts empty on all of them.

    The fix: Read the variable name and script name from the message, select the object, and fill the field. Where the error names an object you cannot find, the log entry is clickable and will select it in the Hierarchy.

    Source: Unity Manual: Null references

  2. You assigned it on the prefab instance, not the asset

    Dragging a reference onto a prefab instance in the scene creates an override on that one instance. Objects spawned from the prefab asset at runtime do not carry it, so the spawned copies throw while the one you set up works perfectly. The reverse also happens: assigning on the asset while the scene instance carries an older override that is still empty.

    The fix: Open the prefab in Prefab Mode and assign the field there, so every instance inherits it. Where an instance already has an override, use the Overrides dropdown on the instance to see what differs and revert it.

    Source: Unity Manual: Editing a prefab in Prefab Mode, Unity Discussions: prefabs not saving reference to gameObject

  3. A prefab asset cannot hold a reference to a scene object

    A prefab lives in the Project window and has no knowledge of any particular scene, so Unity cannot serialise a reference from a prefab asset to an object that only exists in a scene. Attempting it in the Inspector either refuses the drop or silently leaves the field empty, and the spawned object then throws. This is a structural limit rather than a bug, and it catches people who expect the assignment to behave like any other.

    The fix: Invert the direction. Have the scene object find or register itself with the spawned instance after Instantiate, or resolve the dependency at runtime through a manager the prefab can reach. Assigning the reference immediately after Instantiate is the simplest form.

    The spawner lives in the scene, so it can hold both references and connect them.

    using UnityEngine;
    
    public class EnemySpawner : MonoBehaviour
    {
        [SerializeField] private Enemy enemyPrefab;   // project asset
        [SerializeField] private Transform player;    // scene object
    
        public Enemy Spawn(Vector3 position)
        {
            Enemy enemy = Instantiate(enemyPrefab, position, Quaternion.identity);
    
            // The prefab asset could never have stored this itself.
            enemy.SetTarget(player);
            return enemy;
        }
    }
    
    public class Enemy : MonoBehaviour
    {
        private Transform target;
        public void SetTarget(Transform value) => target = value;
    }

    Source: Unity Manual: Prefabs

  4. The field was hidden or renamed, losing its serialised value

    Unity serialises fields by name. Renaming a field in code makes the old saved value orphaned and the new field starts empty, on every object using the script at once. Changing a field's type, or moving it behind a condition that stops it being serialised, has the same effect.

    The fix: Add [FormerlySerializedAs("oldName")] above the renamed field so Unity carries the existing value across. Add it before the rename reaches anyone else's working copy, because it only helps for data that has not already been re-saved.

    FormerlySerializedAs preserves data that would otherwise be lost on rename.

    using UnityEngine;
    using UnityEngine.Serialization;
    
    public class HealthBar : MonoBehaviour
    {
        // Renamed from "img" to "fillImage"; existing scenes and prefabs keep
        // their assigned value because of the attribute.
        [FormerlySerializedAs("img")]
        [SerializeField] private UnityEngine.UI.Image fillImage;
    }

    Source: Unity Scripting API: FormerlySerializedAs

How to prevent it

Validate required references in Awake and disable the component when one is missing. Passing the component as the second argument to Debug.LogError makes the console entry clickable, which turns a hunt through the Hierarchy into one click.

Assign prefab fields in Prefab Mode rather than on an instance, and treat instance overrides as deliberate exceptions rather than the normal way to configure something.

Add [FormerlySerializedAs] whenever you rename a serialised field, and remove it once every scene and prefab has been re-saved. Renaming without it silently empties the field everywhere.

Where a reference is required for a component to work at all, consider whether it can be resolved in Awake instead. A GetComponentInChildren call that cannot fail is better than a field a human has to remember to fill.

Unity version differences

Behaviour is unchanged across supported Unity versions. Prefab Mode and the Overrides dropdown referenced above have been present since the prefab workflow rewrite in Unity 2018.3.

Sources

Frequently asked questions

I did assign it, so why do I still get this error?
Almost always because it was assigned on a different object than the one throwing. Assigning on a prefab instance in the scene does not affect objects spawned from the prefab asset at runtime, and assigning on the asset does not override an instance that already has its own value. Open the prefab in Prefab Mode, check the field there, then check the Overrides dropdown on any instance that behaves differently.
What is the difference between this and NullReferenceException?
UnassignedReferenceException is the more specific case: Unity knows the field is serialised and was meant to be filled in the Inspector, so it says so and names the variable. A NullReferenceException is the general case, covering references that are null for any other reason. The more specific message is more useful because it tells you exactly where to look.
Why can I not drag a scene object onto a prefab?
A prefab is an asset in the Project window and exists independently of any scene, so there is nothing stable for a reference to a scene object to point at. Unity therefore cannot serialise it. Connect the two at runtime instead, typically by having a scene object assign the reference straight after Instantiate.
Will a null check make this error go away?
It will stop the exception, but it will not make the component work, and it hides a configuration mistake that is trivial to fix properly. If a reference is genuinely optional, check it. If it is required, log a clear error naming the object and disable the component, so the missing assignment is obvious rather than silently tolerated.
Why did all my references empty at once?
Renaming or retyping a serialised field is the usual cause, because Unity matches saved data to fields by name. Every object using that script loses the value simultaneously. [FormerlySerializedAs] on the renamed field prevents it, but only if it is added before the affected assets are re-saved.

Last updated: