Finding Missing References in Unity

Missing (sprite) referenceThis post shows a short and simple solution for finding missing references in Unity.

You can get the code from GitHub.

Missing References

A missing reference is different from having no reference at all (in which case the inspector shows “None”). These can occur for a variety of reasons, for example: moving asset files outside of the Unity editor, a result of a mixup in .meta files that results in having a link to an invalid object id (or due to a bug – see this bug).

The major issue is that missing references can be hidden somewhere in the project, only to be found too late in the process. Luckily, we can exercise some editor scripting to the rescue…

Solution

Here is the full code for finding these missing references, in case you run into this issue:

using System.Collections;
using System.Linq;
using UnityEditor;
using UnityEngine;

public class MissingReferencesFinder : MonoBehaviour 
{
	[MenuItem("Tools/Show Missing Object References in scene", false, 50)]
	public static void FindMissingReferencesInCurrentScene()
	{
		var objects = GetSceneObjects();
		FindMissingReferences(EditorApplication.currentScene, objects);
	}

	[MenuItem("Tools/Show Missing Object References in all scenes", false, 51)]
	public static void MissingSpritesInAllScenes()
	{
		foreach (var scene in EditorBuildSettings.scenes.Where(s => s.enabled))
		{
			EditorApplication.OpenScene(scene.path);
			FindMissingReferences(scene.path, GetSceneObjects());
		}
	}

	[MenuItem("Tools/Show Missing Object References in assets", false, 52)]
	public static void MissingSpritesInAssets()
	{
		var allAssets = AssetDatabase.GetAllAssetPaths();
		var objs = allAssets.Select(a => AssetDatabase.LoadAssetAtPath(a, typeof(GameObject)) as GameObject).Where(a => a != null).ToArray();
		
		FindMissingReferences("Project", objs);
	}

	private static void FindMissingReferences(string context, GameObject[] objects)
	{
		foreach (var go in objects)
		{
			var components = go.GetComponents();
			
			foreach (var c in components)
			{
				if (!c)
				{
					Debug.LogError("Missing Component in GO: " + FullPath(go), go);
					continue;
				}
				
				SerializedObject so = new SerializedObject(c);
				var sp = so.GetIterator();
				
				while (sp.NextVisible(true))
				{
					if (sp.propertyType == SerializedPropertyType.ObjectReference)
					{
						if (sp.objectReferenceValue == null
						    && sp.objectReferenceInstanceIDValue != 0)
						{
							ShowError(context, go, c.GetType().Name, ObjectNames.NicifyVariableName(sp.name));
						}
					}
				}
			}
		}
	}

	private static GameObject[] GetSceneObjects()
	{
		return Resources.FindObjectsOfTypeAll()
			.Where(go => string.IsNullOrEmpty(AssetDatabase.GetAssetPath(go))
			       && go.hideFlags == HideFlags.None).ToArray();
	}
	
	private const string err = "Missing Ref in: [{3}]{0}. Component: {1}, Property: {2}";
	
	private static void ShowError (string context, GameObject go, string c, string property)
	{
		Debug.LogError(string.Format(err, FullPath(go), c, property, context), go);
	}
	
	private static string FullPath(GameObject go)
	{
		return go.transform.parent == null
			? go.name
				: FullPath(go.transform.parent.gameObject) + "/" + go.name;
	}
}

Paste this code into an editor folder, load the scene you’d like to find missing references in, and click the menu option “Tools/Find Missing references in scene”.

Any issues found will be shown in the Console (as errors).

Acknowledgements

The original code was improved upon feedback (thanks: Amir Barak, Thomas Viktil, Alex Kogan, Amir Ebrahimi).

The code was updated to include:

  • Error context (can click to get to the game object)
  • Find missing components (not only missing references inside scripts)
  • Find inactive scene objects as well
  • Formatting – keep it all under 80 chars

Grab the code from GitHub and drop a comment if this helped you out with your project 🙂

This entry was posted in Unity and tagged , , , . Bookmark the permalink.