Execution Order of Scripts - Awake and OnEnable

I am facing issues related to scripts execution order and this point is out of my mind though I am an experienced, Unity developer. So I expect a little bit of explanation regarding this.

This is my MenuContoller script code:

public class MainMenuController : MonoBehaviour
{  
     [SerializeField] Text bestScoreText;
     [SerializeField] Toggle soundToggle;
     private void OnEnable()
     {
         Init();
     }
     private void Init()
     {
         if (GameManager.Instance == null)
             Debug.Log("null game manager");
         GameManager.Instance.PlayerLives = 0;
         bestScoreText.text = DataStorage.RetrieveBestScore().ToString("D5");
         SoundManager.Instance.IsSoundEnabled = DataStorage.RetrieveSoundStatus() == GameConstants.STAT_ON ? true : false;
         soundToggle.isOn = !SoundManager.Instance.IsSoundEnabled;
     }
}

This is my GameManager script code:

public class GameManager : MonoBehaviour
{
   private static GameManager instance;
   //
   private int levelIndex;
   private int gameScore;  
   private int playerLives;

   void Awake()
   {
      instance = this;
   }

   public static GameManager Instance
   {
      get
      {
          return instance;
      }
   }
}

I am getting NullReferenceException during execution:

Now I can’t able to understand - how the OnEnable method gets executed before other script’s Awake method?

Because of this reason, I am getting a null reference exception. As per my understanding, all scripts Awake methods get executed first then after OnEanble call for all scripts of the project.

Please explain to me this point so my side confusion gets solved.

Awake is only called before OnEnable within the context of a single script. If you have multiple scripts with these methods, both Awake and OnEnable can get called for one script, before both get called for another one.

Start is always called after Awake and OnEnable for all scripts, though (source).

3 Likes

So as per you saying - all scripts are execute their life cycle methods in order without considering execution order of the script - they just follow their own path.

Am I right in making conclusion?

I’ve talked about this a few times on the forum…
My first ever post about it way back in 2014:

And my most recent in 2018:

I’ll basically repeat myself here though to save you having to navigate there:

Awake on all scripts is called before Start is called on all scripts. As is documented:

OnEnable is independent of that timing. Here we can get an idea of OnEnable’s timing:

So in regards to when a scene is first loaded. OnEnable is called when the object is first enabled. This happens when the instance of the MonoBehaviour is created, and just after Awake. So as a result your singleton isn’t necessarily initialized (has OnEnable called) when MainMenuController has its OnEnable called.

You should either use ‘Start’.
Annoying since if you need OnEnable you have to write a bunch of annoying logic.

OR

Use script execution order.
Annoying because setting up execution order is cumbersome. And isn’t easily readable in code since it’s all through the editor.

OR

I personally used a method where I created my own script called SPComponent. And on it I have a method called ‘OnStartOrEnabled’:

Annoying part is that it requires setting this all up… main reason I only did set this all up is because I personally run into it all the time.

With this I call OnStartOrEnable either in ‘Start’ or in ‘OnEnable’ if and only if Start was already called. Thusly giving you a OnEnable like method that behaves more like Start.

…

NOTE - you may notice if you go to those links that in my 2018 post my source code link doesn’t have OnStartOrEnable. That’s because in my 3.0 library I’ve moved to a mixin system (I’m playing around with mixin ideas to save putting logic on SPComponent in cases its not needed). So now my OnStartOrEnable is implemented with this mixin:

1 Like

You could change the script execution order in the settings, have the GameManager script run before everything else, and use Awake in your first script, that way it is guaranteed that the GameManager’s Awake has already run.

You also could initialize your static singleton reference in the constructor instead of in Awake.

1 Like

Or use FindObjectOfType in GameManager.Instance getter if the instance is null.

This will only find created and enabled objects.

https://docs.unity3d.com/ScriptReference/Object.FindObjectOfType.html

The object may or may not exist yet, and even if it did, it’s not enabled yet.

…

Antistone’s suggestion would/could work.

With one exception… the state of the singleton could get overwritten when the singleton is initialized. Depending on timing it may not have deserialized yet, in which case when OP sets ‘playerLives’ to 0, that might get reset to whatever the serialized value is. That value may happen to be 0 as well, making this bug unnoticeable at first until you maybe change it in some scene randomly, since that 0 is just incidental.

Note serialization/deserialization doesn’t necessarily happen on the main thread either. So this value could be changed at any moment before its Awake is called. And since the timing of this isn’t documented, it could change in the future, or on the target build. Which you could run tests for to determine the behaviour… but I personally don’t like relying on undocumented behaviour. It’s bit me in the butt many times before.

…

Personally if I have a singleton. I create them in the moment rather than allowing them to exist in the scene. Essentially I do like SisusCo… but instead of FindObjectOfType, if it’s null I create an instance. Thusly guaranteeing an initialized instance with its Awake/OnEnable called immediately (since CreateInstance calls these).

The only exception to this is if my singleton is scene specific rather than living the entire project. Which well… I generally avoid this (the exceptions being Unity’s built in singleton like input stuff… which grate on my nerves).

1 Like

As a general rule of thumb, I use Awake() for all internal initialisation, and Start() for anything that depends on other objects in the Scene.

For anyone stumbling upon this in the future, one other thing to consider is that the script execution order only applies after your object is active and enabled. So if you’ve got inactive stuff in your scene, or if you create stuff via code inside your scene, that will impact when their initialisation methods are called.

Does that need to be a MonoBehaviour? Nothing in there references the Unity scene, so you could just have it as a plain old C# class. You even can reference the Unity scene, so long as you don’t need to use the Inspector to configure anything and remember to null out the references when you change scenes (otherwise the referenced objects can’t be cleaned up).

OnEnable, which was used in the original code to assign the instance, will also only run for created and enabled objects, so I don’t see any issue here.

FindObjectOfType is more reliable than assigning the instance in OnEnable, because it works even if other classes try to get the instance before the OnEnable function has fired. So it can always be called from the Awake, OnEnable or Start functions of any other components, and it will just work.

Of course creating the instance automatically if it doesn’t exist yet is also a perfectly valid option. Both methods have their own pros and cons.

For example, if you auto-create the instance, there’s a risk that when unloading a scene, exiting play mode or quitting the application, you will accidentally end up recreating the singleton again and again, as multiple systems refer to the manager, and the program keeps trying to unload all objects in the scene. If you use FindObjectOfType you are somewhat more likely to notice such an issue when you run into NullReferenceExceptions, and can then implement a workaround.

Another risk when auto-creating your singleton is that you might not even notice if your singleton gets unintentionally destroyed by something like a scene loading process, and you lose state, as a new singleton simply pops into existence to take it’s place without you even noticing. For this reason using FindObjectOfType might be the better option when using singletons that are supposed to persist through scene loads and are not stateless.

I agree that this is a good pretty general good rule of thumb to follow, that can reduce the number of NullReferenceException you will encounter during development. However I think that ideally you would also always make sure that internal initialization takes place even if external systems call any public methods or properties on your components before that components Awake method has fired. This is especially important in my opinion when we are talking about a manager script commonly utilized by many other classes, because it only takes one other script making the mistake of referring to the manager at the “wrong” / unexpected time for things to break.

In cases where that’s relevant, sure… but I’m struggling to think of any cases where that’s been a concern for me. I don’t think it’s come up more than maybe half a dozen times in the decade I’ve been using Unity. In such cases, something similar to what the OP is doing seems reasonable - make another method that does the initialization, then call that from any relevant entry point if it hasn’t already been called.

@angrypenguin

I have run into the issue myself a couple of times over the years. Not that many times, I suppose. Each time that I can recall, it happened when the two classes in question were written by different programmers.

I think these things get more important the more people are working on the same project, and the more complex the project is. It’s a similar dynamic as with things like unit tests / assertations: they’re not that important, until your project size grows so large that they are.

Also I suppose that on-demand instance fetching / creation becomes more important when you’re working with editor code, which I happen to be doing a lot :smile:

Yes, OnEnable was used in the original code, and FindObjectOfType would be similar… that’s the problem.

It’s a timing issue.

OP has a timing issue where they’re accessing the singleton during its OnEnable, and the Awake/OnEnable of the singleton has yet to occur.

FindObjectOfType wouldn’t resolve OPs problem since it suffers from the same timing issue.

Analogously OP tried picking up water before it turned to ice with his right hand, and you suggested to use his left hand. Both have the same problem… it’s not ice yet (the singleton hasn’t been initialized yet).

@lordofduct Perhaps you’re not understanding exactly what I’m suggesting?

Consider this simple singleton implementation:

using UnityEngine;

public class GameManager : MonoBehaviour
{
    private static GameManager instance;

    public static GameManager Instance
    {
        get
        {
            if(instance == null)
            {
                instance = Object.FindObjectOfType<GameManager>();
            }
            return instance;
        }
    }
}

And this simple test:

using UnityEngine;

public class TestGameManager : MonoBehaviour
{
    private void Awake()
    {
        Debug.Log("GameManager found during Awake: " + (GameManager.Instance != null));
    }

    private void OnEnable()
    {
        Debug.Log("GameManager found during OnEnable: " + (GameManager.Instance != null));
    }

    private void Start()
    {
        Debug.Log("GameManager found during Start: " + (GameManager.Instance != null));
    }
}

As long as both components exist somewhere in the same scene when it is loaded, GameManager.Instance will never return null during any of these test. Not even if you manually set TestGameManager to always execute before GameManager using the Script Execution Order settings.

Because you’re not relying on the instance being set during some Unity event function, script execution order no longer matters at all.

The only example that I can think of where this would fail is in some sort of weird multi-scene loading scenario where TestGameManager’s scene is loaded before GameManager’s scene. But if you’re building that sort of multi-scene loading system, making it impossible for this to happen should be the first thing you do anyways.

I understood completely what you meant.

My point was that FindObjectOfType only returns enabled/active objects, per the documentation. And due to timing, it may or may not be instantiated/enabled yet, depends on how the scene loads. Which is OP’s original problem.

This might possibly work for you in your test, especially in the editor, if the timing is right. Unfortunately in my 9 years of experience using Unity… timing being one way in the editor doesn’t always reflect the timing in a targeted build.

Case in point… I use aron granberg’s A* pathfinding library in a couple of my released games. His library uses FindObjectOfType for the very purpose you’re describing. Unfortunately I have this really annoying bug out in the wild in one of my titles where scenes have no AI pathfinding because the ordering/timing can be all wrong when built to those target release platforms. Super annoying because all my testing in editor works great! It’s only in the wild that it occurs… I specifically had to hunt down machines with specific hardware specs to even recreate it in a release build.

(on a side note, that same FindObjectOfType also crashes on some machines… I reported it, but never got any response from Unity likely cause it’s not easily reproduceable. I avoid it like the plague now)

If you are relying on Unity to deserialize data into your class, and one way or another the function that wants to reference this class is running before that deserialization occurs, then I’m pretty sure you are screwed no matter how the reference is obtained. To avoid this, you would presumably either need to make sure you never try to reference the class before whatever point at which deserialization is guaranteed to have occurred (which you say is undocumented, so you’d have to guess what that point is) or you would need to avoid any component ever relying on data in any other component that has been set through Unity’s inspector (which strikes me as rather impractical).

I suppose that is technically a risk, but I suspect that a version of Unity that allows some objects to Awake before other objects have been deserialized would break a huge number of existing Unity applications, that makes it pretty unlikely Unity would ever do it. Indirect references like someComponent.someSubComponent are so common and so innocuous that it’s hard to believe any significant fraction of Unity users have completely avoided ever using them from OnEnable or Awake. (Nor is that the limit of the problems; it would also be unsafe to call any functions on any component that relies in any way on any of its serialized data.)

Additionally, note that classes referencing scriptable objects or prefabs would also need some way of knowing when it is safe to assume that they have been deserialized, and since they never Awake, that couldn’t be the rule. You could drive yourself crazy trying to prepare for every possible future system Unity could ever use for this, but it really seems to me that Unity’s only sensible option is guaranteeing that all objects deserialize before any object Awakes.

I mean yeah… Unity in their own documentation even says don’t rely on the data in any other component during Awake. It says you should only setup relationships during Awake, but access data on those objects in Start or later.

Mind you when Instantiate is called, it pushes it through the entire creation/awake/onenable process for you so that it can immediately be accessed the line after calling Instantiate.

And OP’s original problem all stems from that ordering/timing. OnEnable happens just after Awake, rather than just before Start, relative to other components. It gets this weird grey area of behaviour where the first time its called it could potentially be before Awake has been called on any other object. Where as if it’s called later on (because you toggled its enabled property), then it is safe to access all other objects. It’s an annoying duality to is operation.

So as a result its bad to access the state/data of another object during OnEnable, similar to Awake. Because you might be accessing another object that has yet to be initialized. Set up relationships… sure, but don’t access.

This is why I use my OnStartOrEnable, which removes this duality.

…

Back at your option of the constructor. It doesn’t necessarily resolve that duality. Sure, in most cases the deserialization has likely occurred (some build targets depending version ‘might’ behave differently, but those are edge cases). But it limits OP in that they can’t use Awake in the GameManager singleton anymore if another object attempts to modify its state BEFORE its Awake is even called.

The big take away I wanna stress is… be aware of WHY the problem exists so OP can work around it. And as a result I prefer methodologies that take those into consideration so you don’t run into other gotchas. Like yes, the constructor will resolve the null reference exception in 99.999999% of cases (since yes, technically the serialization issue probably won’t hurt them). But now in a month say they do something in Awake of their singleton like set playerLives, they’re going to get unexcepted behaviour since they didn’t really resolve the root of the issue. They just patched around it.

Could you please cite exactly where you read that? It seems at odds with this:

“Awake is called after all objects are initialized so you can safely speak to other objects or query them”

Same place, it’s like 2 sentences later:

Looking at the documentation, it does seem to suggest that it will have been initialized (deserialized I guess you can say) during Awake. Though I’ve had odd behaviour personally on target builds over years where that is unreliable.

I instead rely on this specific part about setting up references to other object, but don’t pass information (data) back and forth until Start.

And like I stated in this most recent post. I’m more concerned about the all the intialization along the process. Both from Unity and by the user.

That’s kind of a misleading fragment to quote without context.

That preceding sentence makes it pretty clear that they’re talking about script execution order, NOT object deserialization.