Error when trying to invoke an event

So I’m making a turn-based multiplayer game, and I’m trying to make a public event happen every time a turn is switched, so the player look frozen if it’s not their turn, but this error happens every time I try to invoke it.

This is the code for my GameManager object.

using UnityEngine;
using TMPro;
using Unity.Netcode;
using UnityEngine.Events;

public class GameLogic : NetworkBehaviour
{
    public int redLives = 4;
    public int blueLives = 4;
    public NetworkVariable<bool> redTurn = new NetworkVariable<bool>(true);
    public NetworkVariable<bool> blueTurn = new NetworkVariable<bool>(true);
    public NetworkVariable<float> turnTimer = new NetworkVariable<float>();
    public NetworkVariable<int> turnCount = new NetworkVariable<int>();

    public int eventRNG;
    public TMP_Text text;
    public TeamDistribution mp;
    private int turnTimerDisplay;

    public UnityEvent TSEvent;

    private void Awake()
    {
        QualitySettings.vSyncCount = 0;
        Application.targetFrameRate = 60;
    }
    void Update()
    {
        turnTimerDisplay = Mathf.RoundToInt(turnTimer.Value);
        text.text = "Round " + turnCount.Value + "\r\nNext round in " + (20 - turnTimerDisplay) + "\r\nRed players: " + mp.redTeamPlayers.Value + "\r\nBlue players: " + mp.blueTeamPlayers.Value + "\r\nRed turn: " + redTurn.Value + "\r\nBlue turn: " + blueTurn.Value;
        turnTimer.Value += Time.deltaTime;
        if (turnTimer.Value >= 20)
        {
            TurnSwitch(); //this function does not get called at all unless i remove the invoke event line, the timer goes above 20
        }
    }

    public void TurnSwitch()
    {
        TSEvent?.Invoke();   //if i deactivate this line no error happens

        if (redTurn.Value == true && blueTurn.Value == true)
        {
            bool turnRNG = Random.Range(0, 2) == 0;
            if (turnRNG)
            {
                blueTurn.Value = true;
                redTurn.Value = false;
            }
            else
            {
                redTurn.Value = true;
                blueTurn.Value = false;
            }
            turnTimer.Value = 0;
            turnCount.Value += 1;
        }
        else if (redTurn.Value == true)
        {
            redTurn.Value = false;
            blueTurn.Value = true;
            turnTimer.Value = 0;
            turnCount.Value += 1;
        }
        else if (blueTurn.Value == true)
        {
            redTurn.Value = true;
            blueTurn.Value = false;
            turnTimer.Value = 0;
            turnCount.Value += 1;
        }
    }
}

This is the code for my player prefab.

using UnityEngine;
using UnityEngine.UI;
using Unity.Netcode;
using TMPro;

public class Movement : NetworkBehaviour
{
    public Vector3 velocity;
    public float acceleration = 8;
    public float deceleration = 60;
    public float maxSpeed = 15;
    public float jumpHeight = 2;

    float distanceToCheck = 1.5f;
    float horizontalDistanceToCheck = 1f;
    public bool isGrounded;
    public RaycastHit hit;
    public ParticleSystem hermesBoots;
    public float highJumpTimer = 0;
    public float highJumpTimerMax = 12;
    private float speen;
    public float maxHealth = 400;
    public float currentHealth = 400;
    public float currentMana = 25;
    public float maxMana = 25;
    public float manaCounter = 0;
    public float manaRegenRate = 1;
    public float terminalVelocity = -20;
    public float gravity = 0.7f;


    public int kills = 0;
    public int score = 1;
    public float environmentIFrames;
    public GameLogic gameLogic;
    public GameObject ice;
    public bool blueTeam = false;
    public bool redTeam = false;
    private Vector3 startPos;
    public TeamDistribution mp;
    private GameObject clone;
    public GameObject healthBar;
    public GameObject healthText;
    public Camera cam;

    void Awake()
    {
        gameLogic = FindObjectOfType<GameLogic>();
        mp = FindObjectOfType<TeamDistribution>();
        healthBar = GameObject.Find("HealthBarInner");
        healthText = GameObject.Find("HealthText");
        cam = FindObjectOfType<Camera>();
    }

    private void Start()
    {
        CameraSetup();
        if (mp.blueTeamPlayers.Value == mp.redTeamPlayers.Value)
        {
            redTeam = Random.Range(0, 2) == 0;
            if (redTeam)
            {
                blueTeam = false;
                mp.redTeamPlayers.Value += 1;
            }
            else
            {
                blueTeam = true;
                mp.blueTeamPlayers.Value += 1;
            }
        }

        else if (mp.blueTeamPlayers.Value > mp.redTeamPlayers.Value)
        {
            redTeam = true;
            blueTeam = false;
            mp.redTeamPlayers.Value += 1;
        }

        else if (mp.blueTeamPlayers.Value < mp.redTeamPlayers.Value)
        {
            redTeam = false;
            blueTeam = true;
            mp.blueTeamPlayers.Value += 1;
        }


        if (blueTeam)
        {
            startPos = new Vector3(-66, 80, 0);
        }
        if (redTeam)
        {
            startPos = new Vector3(66, 80, 0);
        }
        transform.position = startPos;
    }

    private void CameraSetup()
    {
        if (!IsOwner) return;
        cam.GetComponent<PlayerFollow>().setTarget(gameObject.transform);
    }

    private void Update()
    {
        if (!IsOwner) return;
        healthBar.GetComponent<Image>().fillAmount = currentHealth / maxHealth;
        healthText.GetComponent<TMP_Text>().text = "Life: " + currentHealth + "/" + maxHealth;

        float velocityAbsolute = Mathf.Abs(velocity.x);
        Vector3 stepupBottomPosition = new Vector3(transform.position.x, transform.position.y - 1.3f, transform.position.z);
        Vector3 groundPositionL = new Vector3(transform.position.x - 0.7f, transform.position.y, transform.position.z);
        Vector3 groundPositionR = new Vector3(transform.position.x + 0.7f, transform.position.y, transform.position.z);
        Ray groundCheck = new Ray(transform.position, Vector3.down);
        Ray groundCheckL = new Ray(groundPositionL, Vector3.down);
        Ray groundCheckR = new Ray(groundPositionR, Vector3.down);
        if (Physics.Raycast(groundCheck, out hit, distanceToCheck) || Physics.Raycast(groundCheckL, out hit, distanceToCheck) || Physics.Raycast(groundCheckR, out hit, distanceToCheck))
        {
            isGrounded = true;
        }
        else
        {
            isGrounded = false;
        }

        Ray stepupTop = new Ray(transform.position, Vector3.right * Input.GetAxisRaw("Horizontal"));
        Ray stepupBottom = new Ray(stepupBottomPosition, Vector3.right * Input.GetAxisRaw("Horizontal"));
        bool topCheck = Physics.Raycast(stepupTop, out hit, horizontalDistanceToCheck);
        bool bottomCheck = Physics.Raycast(stepupBottom, out hit, horizontalDistanceToCheck);


        if (gameLogic.blueTurn.Value == true && blueTeam || gameLogic.redTurn.Value == true && redTeam)
        {
            if (!topCheck && bottomCheck)
            {
                if (isGrounded)
                {
                    transform.position = new Vector3(transform.position.x, transform.position.y + 1, transform.position.z);
                }
                else
                {
                    transform.position = new Vector3(transform.position.x + Input.GetAxisRaw("Horizontal"), transform.position.y + 1, transform.position.z);
                    velocity.x = 0;
                }
            }
            if (topCheck)
            {
                velocity.x = 0 * Input.GetAxisRaw("Horizontal");
            }


            if (Input.GetAxisRaw("Horizontal") == 1 && isGrounded || Input.GetAxisRaw("Horizontal") == -1 && isGrounded)
            {
                velocity.x = Mathf.MoveTowards(velocity.x, Input.GetAxisRaw("Horizontal") * maxSpeed, acceleration * Time.deltaTime);
            }
            else
            {
                if (Input.GetAxisRaw("Horizontal") == 1 && !isGrounded || Input.GetAxisRaw("Horizontal") == -1 && !isGrounded)
                    if (velocityAbsolute < 4)
                    {
                        velocity.x = Mathf.MoveTowards(velocity.x, Input.GetAxisRaw("Horizontal") * 4, acceleration * Time.deltaTime);
                    }
                    else
                    {

                    }
                else if (Input.GetAxisRaw("Horizontal") == 0)
                {
                    velocity.x = Mathf.MoveTowards(velocity.x, 0, deceleration * Time.deltaTime);
                }
            }


            if (isGrounded && !Input.GetKeyDown(KeyCode.Space))
            {
                highJumpTimer = 0;
            }
            if (Input.GetKeyDown(KeyCode.Space) && isGrounded || highJumpTimer > 0 && Input.GetKey(KeyCode.Space) && highJumpTimer < highJumpTimerMax)
            {
                velocity.y = jumpHeight;
                highJumpTimer += 1;
            }
            if (Input.GetKeyUp(KeyCode.Space))
            {
                highJumpTimer = 0;
            }

            if (isGrounded && highJumpTimer == 0)
            {
                velocity.y = 0;
            }
            else
            {
                if (velocity.y >= terminalVelocity && gameLogic.blueTurn.Value == true && blueTeam || velocity.y >= terminalVelocity && gameLogic.redTurn.Value == true && redTeam)
                {
                    velocity.y -= gravity;
                }

            }
            transform.position += velocity * Time.deltaTime;
            transform.rotation = Quaternion.Euler(0, speen, 0);
        }

        if (gameLogic.redTurn.Value == true && gameLogic.blueTurn.Value == false && blueTeam || gameLogic.blueTurn.Value == true && gameLogic.redTurn.Value == false && redTeam)
        {
            velocity.x = 0;
            velocity.y = 0;
        }


        if (Input.GetAxisRaw("Horizontal") == 1)
        {
            speen = 0;
        }
        else if (Input.GetAxisRaw("Horizontal") == -1)
        {
            speen = 180;
        }


        if (currentHealth <= 0)
        {
            gameLogic.blueLives -= 1;
            score -= 1;
            transform.position = startPos;
            currentHealth = maxHealth;
        }
        if (environmentIFrames > 0)
        {
            environmentIFrames -= Time.deltaTime;
        }


        if (velocity.x == 0 && isGrounded)
        {
            manaRegenRate = (maxMana / 7 + 1 + maxMana / 2) * (currentMana / maxMana * 0.8f + 0.2f) * 1.15f;
        }
        else
        {
            manaRegenRate = (maxMana / 7 + 1) * (currentMana / maxMana * 0.8f + 0.2f) * 1.15f;
        }

        if (currentMana < maxMana)
        {
            manaCounter += manaRegenRate;
        }
        if (manaCounter >= 120 && currentMana < maxMana)
        {
            currentMana += 1;
            manaCounter = 0;
        }   
    }

    private void OnTriggerStay(Collider collider)
    {
        if (environmentIFrames <= 0)
        {
                if (collider.tag == "Lava")
                {
                    currentHealth -= 80;
                    environmentIFrames = 0.66f;
                }
                if (collider.tag == "Tornado")
                {
                    currentHealth -= 10;
                    environmentIFrames = 0.66f;
                }
                if (collider.tag == "Geyser")
                {
                    currentHealth -= 30;
                    environmentIFrames = 0.66f;
                }
                if (collider.tag == "Fireball")
                {
                    currentHealth -= 40;
                    environmentIFrames = 0.66f;
                }
                if (collider.tag == "Lightning")
                {
                    currentHealth -= 60;
                    environmentIFrames = 0.66f;
                }
        }
    }

    [ServerRpc]
    public void IceRenderServerRpc()
    {
        if (gameLogic.redTurn.Value == true && gameLogic.blueTurn.Value == false && blueTeam || gameLogic.blueTurn.Value == true && gameLogic.redTurn.Value == false && redTeam)
        {
            clone = Instantiate(ice, transform.position, transform.rotation);
            clone.GetComponent<NetworkObject>().Spawn(true);
            clone.transform.rotation = Quaternion.Euler(-90, 90, 90);
            clone.transform.position = transform.position + new Vector3(0, 1, 0);
        }
        else
        {
            Destroy(clone.gameObject);
        }
    }
}

P.s. sorry for the bad code, I’m only getting started with unity.

@nb070507

Could you include the Movement.cs script as well? This is where the exception is actually happening.
My guess, looking at the code provided, is that the NetworkObject associated with Movement.IceRenderServerRpc is possibly not spawned yet?
Really, it might be easier to do something like this:

    public class MyTeamTurnSystem : NetworkBehaviour
    {
        public enum TeamTypes
        {
            Red,
            Blue
        }

        public int TurnTimeOut = 20;

        private Coroutine m_TurnTimeoutCoroutine;
        private NetworkVariable<bool> m_TeamsCanStart= new NetworkVariable<bool>();

        // Server-host assigns this or perhaps you could pre-assign it depending upon your design
        private NetworkVariable<TeamTypes> m_AssignedTeam = new NetworkVariable<TeamTypes>();


        private NetworkVariable<TeamTypes> m_CurrentTeamTurn = new NetworkVariable<TeamTypes>();  
        private List<string> m_TeamTypesNames;

        public override void OnNetworkSpawn()
        {
            if(IsServer)
            {
                m_TeamsCanStart.Value = false;
                // Get the types
                m_TeamTypesNames = Enum.GetNames(typeof(TeamTypes)).ToList();
                // Alternate assignment
                m_AssignedTeam.Value = (TeamTypes)Enum.Parse(typeof(TeamTypes), m_TeamTypesNames[m_TeamTypesNames.Count % NetworkManager.ConnectedClientsIds.Count]);
            }

            base.OnNetworkSpawn();
        }

        // invoke this when you want the 1st team turn to start.
        // most likely controlled by some other game state/condition (i.e. both sides are ready)
        public void StartTeamTurns(TeamTypes teamToStart)
        {
            // Only server/host should invoke this
            if (!IsServer)
            {
                return;
            }
            m_TeamsCanStart.Value = true;
            m_CurrentTeamTurn.Value = teamToStart;

            NextTeamTurn(teamToStart, true);
        }

        private IEnumerator TeamTurnTimeout(float timeoutPeriod)
        {
            var timeoutWait = new WaitForSeconds(0.5f);
            var turnTimedOut = Time.realtimeSinceStartup + timeoutPeriod;
            var currentTeam = m_CurrentTeamTurn.Value;
            while (currentTeam == m_CurrentTeamTurn.Value)
            {
                yield return timeoutWait;
                if (timeoutPeriod < Time.realtimeSinceStartup)
                {
                    NextTeamTurn(m_CurrentTeamTurn.Value);
                    break;
                }
            }
            yield break;
        }

        private void NextTeamTurn(TeamTypes currentTeam, bool keepCurrentTeam = false)
        {
            if (m_TurnTimeoutCoroutine != null)
            {
                StopCoroutine(m_TurnTimeoutCoroutine);
            }
            if (!keepCurrentTeam)
            {
                var teamIndex = m_TeamTypesNames.IndexOf(m_CurrentTeamTurn.Value.ToString());
                teamIndex++;
                m_CurrentTeamTurn.Value = (TeamTypes)Enum.Parse(typeof(TeamTypes), m_TeamTypesNames[teamIndex % m_TeamTypesNames.Count]);
            }
            m_TurnTimeoutCoroutine = StartCoroutine(TeamTurnTimeout(TurnTimeOut));
        }

        // Invoke this when the team has finished their turn
        public void TeamTurnFinished()
        {
            if (IsServer)
            {
                NextTeamTurn(m_CurrentTeamTurn.Value);
            }
            else
            {
                TeamTurnFinishedServerRpc();
            }      
        }


        [ServerRpc(RequireOwnership = false)]
        private void TeamTurnFinishedServerRpc()
        {
            NextTeamTurn(m_CurrentTeamTurn.Value);
        }

        private void Update()
        {
            // Don't do anything if not spawned or teams cannot have a turn yet
            if (!IsSpawned || !m_TeamsCanStart.Value)
            {
                return;
            }

            // Exit early if it isn't your teams turn
            if (m_AssignedTeam.Value != m_CurrentTeamTurn.Value)
            {
                return;
            }

            // Update Team Turn action or the like for the players or what have you
            // i.e.
            // UpdateTeamAction();
        }
    }

Where you are only updating if it is your team’s turn… the above is a general pseudo code approach… and is just another way to handle it… depending on whether you want a global team turn management system or the like depends on how you want to use the above code… but gives you the general idea.

I did include the Movement script lower, but thank you for the reply.
IceRenderServerRpc is a function I used to spawn the ice object to make the players look frozen, but now that I learned animation I will just get rid of it. Will keep you updated.