Exceptions
Keywordstry, catch, finally, throw, when
CategoryError handling
In UnityThe red errors in the Console: NullReferenceException, MissingReferenceException...

Exceptions & try/catch

An exception is C#'s way of saying "something went wrong and I can't continue". If nothing handles it, Unity prints a red error in the Console and skips the rest of that method. A try/catch block lets you handle the problem yourself.

A tightrope walker with a safety net. The code inside try is the walk. If the walker falls (an exception), the catch is the net that catches them, so the show can go on. finally is the crew who clean up the stage afterwards, whether the walker made it across or fell.

Syntax

try
{
    // Code that might fail
}
catch (SpecificException ex)
{
    // Runs only if that kind of exception happened
}
catch (Exception ex)
{
    // Catches anything else (put the most general one last)
}
finally
{
    // ALWAYS runs: after try succeeds, after a catch, even after a return
}

What Unity does with an unhandled exception

  1. Your code throws, e.g. you call a method on a null variable in Update.
  2. C# stops running that method immediately, and walks back up through the methods that called it, looking for a matching catch.
  3. If none is found, Unity catches it at the top, logs a red error with the stack trace, and moves on to the next script's Update.
  4. The game doesn't crash, but everything after the error line in that method was skipped. Next frame it runs again, and probably fails again, which is why you see the same error hundreds of times.
  5. Inside a coroutine, an unhandled exception stops that coroutine for good.
Bullet.Spawn() throw!Weapon.Fire()Player.Update()Unity engine (calls Update)call stack (most recent on top)unwindsa try/catch here would stop itNo catch anywhere:Unity logs a red error
When Bullet.Spawn() throws, C# abandons it and each caller in turn, looking for a matching catch. If none is found, Unity catches it, logs the red Console error, and moves on to the next script, so the rest of Player.Update() is skipped this frame.

When to use try/catch in Unity

Use it for things outside your control that can fail even when your code is correct:

Don't use it to hide bugs in your own code. A NullReferenceException from an unassigned field should be fixed, not caught.

Code Samples

Loading a save file safely

using System;
using System.IO;
using UnityEngine;

public static class SaveSystem
{
    private static string SavePath => Path.Combine(Application.persistentDataPath, "save.json");

    public static SaveData Load()
    {
        try
        {
            string json = File.ReadAllText(SavePath);
            SaveData data = JsonUtility.FromJson<SaveData>(json);
            return data ?? new SaveData(); // FromJson can return null for empty text
        }
        catch (FileNotFoundException)
        {
            // First time playing: not an error.
            return new SaveData();
        }
        catch (Exception ex)
        {
            // Corrupt file or no permission: tell the developer, but keep the game running.
            Debug.LogError($"Could not load save: {ex.Message}");
            return new SaveData();
        }
    }

    public static void Save(SaveData data)
    {
        string tempPath = SavePath + ".tmp";
        try
        {
            // Write to a temp file first, so a crash mid-write can't destroy the real save.
            File.WriteAllText(tempPath, JsonUtility.ToJson(data));
            File.Copy(tempPath, SavePath, overwrite: true);
        }
        catch (IOException ex)
        {
            Debug.LogError($"Could not save: {ex.Message}");
        }
        finally
        {
            if (File.Exists(tempPath)) File.Delete(tempPath); // clean up either way
        }
    }
}

[Serializable]
public class SaveData
{
    public int level = 1;
    public int coins;
}

The ?? here is fine because SaveData is a plain C# class, not a Unity object.

Parsing without exceptions: TryParse

Many .NET types offer a Try... method that returns false instead of throwing. It's faster and cleaner than try/catch.

// Throws FormatException on bad input:
int a = int.Parse(inputField.text);

// Better: no exception, just check the result
if (int.TryParse(inputField.text, out int amount))
{
    GiveCoins(amount);
}
else
{
    errorLabel.text = "Please enter a number.";
}

Unity's own APIs follow the same idea: TryGetComponent, Dictionary.TryGetValue.

Throwing your own exceptions

Throw when a method is used wrongly in a way the caller must fix.

public void SetVolume(float volume)
{
    if (volume < 0f || volume > 1f)
        throw new ArgumentOutOfRangeException(nameof(volume), "Volume must be between 0 and 1.");
    // ...
}

Keeping one bad listener from breaking the others

foreach (var listener in listeners)
{
    try
    {
        listener.OnGameSaved();
    }
    catch (Exception ex)
    {
        Debug.LogException(ex); // logs with the full stack trace, then continues the loop
    }
}

Common exceptions in Unity

ExceptionUsually meansFix
NullReferenceExceptionYou used a variable that's null: an unassigned Inspector field, or GetComponent found nothingDouble-click the error; check which variable on that line is null
MissingReferenceExceptionThe object was destroyed, but you still use itCheck != null before use; unsubscribe events in OnDisable
UnassignedReferenceExceptionA serialized field was never assigned in the InspectorAssign it, or check in Awake and log a clear error
IndexOutOfRangeException / ArgumentOutOfRangeExceptionArray/list index is negative or ≥ CountLoop with i < array.Length, not <=
KeyNotFoundExceptiondictionary[key] for a key that isn't thereUse TryGetValue
InvalidOperationException"Collection was modified" while looping over it with foreach; or reading old Input with only the new Input System onLoop backwards with for; see Handling Input
StackOverflowExceptionA method or property calls itself foreverUsually crashes the Editor; check recursive calls and properties

Common Mistakes

See also