clockworklabs/SpacetimeDB · error · InvalidOperationException

SpacetimeDBNetworkManager is a singleton and should only be

Error message

SpacetimeDBNetworkManager is a singleton and should only be attached once.

What it means

Unity-only MonoBehaviour that ticks all active SpacetimeDB connections. Awake guards a static _instance so exactly one manager exists (its Update/OnDestroy iterate a global connection list). A second instance throws InvalidOperationException from Awake, which in Unity also disables that component. ResetStaticFields clears the static on play-mode start to survive disabled domain reloading.

Source

Thrown at sdks/csharp/src/SpacetimeDBNetworkManager.cs:36

        /// AutoStaticsCleanup and NoAutoStaticsCleanup is only supported in Unity 6+
        /// </summary>
        /// <remarks>
        /// See the <see href="https://docs.unity3d.com/6000.5/Documentation/Manual/domain-reloading.html">Unity Domain Reloading Manual</see> 
        /// and the <see href="https://docs.unity3d.com/6000.5/Documentation/ScriptReference/RuntimeInitializeOnLoadMethodAttribute.html">RuntimeInitializeOnLoadMethodAttribute API Docs</see> for details.
        /// </remarks>
        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
        private static void ResetStaticFields()
        {
            _instance = null;
        }

        public void Awake()
        {
            // Ensure that users don't create several SpacetimeDBNetworkManager instances.
            // We're using a global (static) list of active connections and we don't want several instances to walk over it several times.
            if (_instance != null)
            {
                throw new InvalidOperationException("SpacetimeDBNetworkManager is a singleton and should only be attached once.");
            }
            else
            {
                _instance = this;
            }
        }

        private readonly List<IDbConnection> activeConnections = new();

        public bool AddConnection(IDbConnection conn)
        {
            if (activeConnections.Contains(conn))
            {
                return false;
            }
            activeConnections.Add(conn);
            return true;

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Search all loaded scenes for SpacetimeDBNetworkManager and keep exactly one
  2. Bootstrap the manager once in an init scene before additive scenes load
  3. When creating it programmatically, guard with FindObjectOfType<SpacetimeDBNetworkManager>() before AddComponent

Example fix

// before
gameObject.AddComponent<SpacetimeDBNetworkManager>(); // throws if one already exists

// after
if (FindObjectOfType<SpacetimeDBNetworkManager>() == null)
    gameObject.AddComponent<SpacetimeDBNetworkManager>();
Defensive patterns

Strategy: validation

Validate before calling

if (FindObjectOfType<SpacetimeDBNetworkManager>() != null)
    return; // singleton already present in a loaded scene
gameObject.AddComponent<SpacetimeDBNetworkManager>();

Type guard

static bool ManagerExists() => FindObjectOfType<SpacetimeDBNetworkManager>() != null;

Try / catch

try { gameObject.AddComponent<SpacetimeDBNetworkManager>(); }
catch (InvalidOperationException) { /* duplicate instance: destroy this GameObject and reuse the existing manager */ }

Prevention

When it happens

Trigger: The manager GameObject exists in two simultaneously loaded scenes (additive scene loading), a prefab with the component instantiated alongside a scene copy, or a DontDestroyOnLoad instance plus a duplicate in a reloaded scene.

Common situations: Adding SpacetimeDBNetworkManager to both the bootstrap scene and gameplay scenes 'to be safe'; duplicating a prefab that carries it; multi-scene Unity setups.


AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16). Data as JSON: /api/errors/364d7604bd83b9da. Report an issue: GitHub.