Who resets member variables after Awake() has been called?

I have a MonoBehaviour that has an ExecuteInEditor attribute. When I run the game from editor, it crashes deterministically on OnEnabled() because all the data members are in their uninitialized state. I have a following test script that replicates this issue:

using UnityEngine;
using System.Collections.Generic;

[ExecuteInEditMode]
public class ExecuteInEditorTest : MonoBehaviour
{
	List<string> callHistory = new List<string>();
	System.Object testMember = null;
	
	void Awake()
	{
		callHistory.Add("Awake");
		testMember = new System.Object();
	}
	
	void Start()
	{
		callHistory.Add("Start");	
	}
	
	void OnDestroy()
	{
		callHistory.Add("OnDestroy");	
	}
	
	void OnEnable()
	{
		callHistory.Add("OnEnable");
		if (testMember == null)
		{
			foreach (string call in callHistory)
			{
				Debug.Log(call);	
			}
		}
	}
	
	void OnDisable()
	{
		callHistory.Add("OnDisable");	
	}
}

When I run a test scene from editor, the script logs

Awake
OnEnable
Start
OnEnable

or

Awake
OnEnable
OnEnable

Any idea who sets the testMember to null and when? And why the call history is not always the same?

The test scene has just one empty game object with this MonoBehaviour and the default camera.

Cheers,

Antti

Scripts in edit mode need to be able to survive Unity serializing them and recreating them. I’m not sure under which scenarios that happens, but it is quite often - starting and ending play mode is one scenario.

The Unity blog has a recent post that describes this sort of thing in detail, and how to do it right.