Illustrative diagram, not a captured Hierarchy: reloading Boot in the same Play session creates a new copy beside the survivor
Illustrative diagram, not a captured Hierarchy: reloading Boot in the same Play session creates a new copy beside the survivor

The cause is a Boot-scene reload in the same run, not a full restart

DontDestroyOnLoad preserves the existing object across a scene load. It does not stop a new GameManager placed in the reloaded scene from running Awake. A full process restart destroys the previous runtime object, so that is a different event.

In an empty Unity 6000.5.3f1 project, Boot→Game→Boot→Game→Boot produced next-frame manager counts of 1→2→3 without a guard. All three objects were in the special DontDestroyOnLoad scene, and the first Entity ID survived every reload.

Same Play session: Boot → Game → Boot → Game → Boot
No guard, next frame: 1 → 2 → 3
Guarded, next frame: 1 → 1 → 1

Keep the survivor and reject the fresh copy in Awake

Put GameManager on a root GameObject. The Unity 6.5 contract allows DontDestroyOnLoad only on root GameObjects or components attached to roots; preserving the root also preserves its children.

The guarded run still called Awake three times, but destroyed the two new copies. The next-frame counts stayed at 1→1→1 and the first survivor kept the same Entity ID.

using UnityEngine;

public sealed class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }

    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
    private static void ResetStatics()
    {
        Instance = null;
    }

    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }

        Instance = this;
        DontDestroyOnLoad(gameObject);
    }

    private void OnDestroy()
    {
        if (Instance == this)
            Instance = null;
    }
}

A duplicate can exist briefly after Destroy

Destroy does not remove the object on the calling line; Unity performs the actual destruction after the current Update loop. The reproduction observed a maximum of two guarded objects during the duplicate Awake, then one on the next frame. Count or assert after a frame, not immediately after Destroy.

Domain Reload disabled is a separate static-state boundary

Reloading Boot creates a new scene instance during one Play session. Disabling Domain Reload can instead retain static fields and static event handlers between Play sessions.

This boundary was tested with two consecutive Play sessions in the same Editor process. On the second Play entry, SubsystemRegistration observed the previous session's three Awake calls and two destroyed duplicates before resetting the static values. The second session therefore ended at three Awake calls again instead of accumulating to six. Both Play sessions produced 1→2→3 unguarded and 1→1→1 guarded counts.

Avoiding routes back into Boot reduces the chance of duplication, but keep the guard so one accidental scene transition cannot create another manager.

Verification scope

Direct reproduction

Verified

Test environmentUnity 6000.5.3f1 (c2eb47b3a2a9), Windows 10 22H2, empty project, batchmode/nographics; default Domain Reload plus two consecutive Play sessions in one Editor process with Domain Reload disabled

Ran Driver→Boot→Game→Boot→Game→Boot once with default Domain Reload and twice consecutively in the same Editor process with Domain Reload disabled. Every session produced 1→2→3 unguarded and 1→1→1 guarded counts. On the second Play entry, SubsystemRegistration observed the prior static values of three Awake calls and two destroyed duplicates before resetting them, and the current-session count restarted at three rather than accumulating to six.