SceneManager.LoadScene not working ONLY when it is in IEnumerator functions

I’ve experienced a weird error: when I call SceneManager.LoadScene in any (emphasis on any) IEnumerator function, it doesn’t work.
Here’s an example of what isn’t working:

IEnumerator TagDisplay()
    {
        yield return new WaitForSeconds(updateSpeed);
        float tagsActive = GameObject.FindGameObjectsWithTag(tagToSearchFor).Length;
        
        if (tagsActive < 1)
        {
            tagText.text = ifNoTagsLeft;
            yield return new WaitForSeconds(5);
            Debug.Log("hi!");
            if (setHighScore)
            {
                setHighScore = false;
                highscoreObject.timerStop = true;
                Debug.Log("Score set!");
            }
            //LoadLevel();
            if (levelToMoveToElseBlank != "")
            {
                SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1); //go to next level once enemies are dead
            }
            else
            {

                SceneManager.LoadScene(levelToMoveToElseBlank); //go to next level once enemies are dead
                Debug.Log("Level loaded!");
            }

        }
        else
        {
            tagText.text = introString + tagsActive.ToString();
        }
        StartCoroutine(TagDisplay());
    }

Another example of code that doesn’t work:

IEnumerator TagDisplay()
    {
        yield return new WaitForSeconds(updateSpeed);
        float tagsActive = GameObject.FindGameObjectsWithTag(tagToSearchFor).Length;
        
        if (tagsActive < 1)
        {
            tagText.text = ifNoTagsLeft;
            yield return new WaitForSeconds(5);
            Debug.Log("hi!");
            if (setHighScore)
            {
                setHighScore = false;
                highscoreObject.timerStop = true;
                Debug.Log("Score set!");
            }
            LoadLevel();
            

        }
        else
        {
            tagText.text = introString + tagsActive.ToString();
        }
        StartCoroutine(TagDisplay());
    }

    void LoadLevel()
    {
        if (levelToMoveToElseBlank != "")
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1); //go to next level once enemies are dead
        }
        else
        {
            
            SceneManager.LoadScene(levelToMoveToElseBlank); //go to next level once enemies are dead
            Debug.Log("Level loaded!");
        }
        /*
        Debug.Log("Level loaded!");
        SceneManager.LoadScene(levelToMoveToElseBlank);
        */
    }

Strangest of all… this used to work. This code worked in my game and all my other scenes for nearly six weeks. Somehow, I seem to have screwed up every IEnumerator in my project sometime in the last week or two. If I use Debug.Log(“hi”) in an IEnumerator, it still prints out after a few seconds, but it never runs the scene change after a delay.

Some code I ended up writing that does work (it loads the next level instantly, which is a little jarring):

void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Player")
        {
            
            //FractureManager.collisionNum++;
            Destroy(gameObject);

            //yield return new WaitForSeconds(0.01f);
            /*
            brokenPiece1.transform.localScale = originalPiece.transform.lossyScale * 49f;
            brokenPiece2.transform.localScale = originalPiece.transform.lossyScale * 49f;
            brokenPiece3.transform.localScale = originalPiece.transform.lossyScale * 49f;
            brokenPiece4.transform.localScale = originalPiece.transform.lossyScale * 49f;
            brokenPiece5.transform.localScale = originalPiece.transform.lossyScale * 49f;
            brokenPiece6.transform.localScale = originalPiece.transform.lossyScale * 49f;
            brokenPiece7.transform.localScale = originalPiece.transform.lossyScale * 49f;
            */

            //clone = brokenPiece.transform.localScale = originalPiece.transform.lossyScale;
            if (!shattered)
            {
                shattered = true;
                GameObject clone;
                clone = Instantiate(brokenPiece, originalPiece.position, originalPiece.rotation);
                clone.transform.GetChild(0).gameObject.transform.localScale = originalPiece.transform.lossyScale * 49;
                clone.transform.GetChild(1).gameObject.transform.localScale = originalPiece.transform.lossyScale * 49;
                clone.transform.GetChild(2).gameObject.transform.localScale = originalPiece.transform.lossyScale * 49;
                clone.transform.GetChild(3).gameObject.transform.localScale = originalPiece.transform.lossyScale * 49;
                clone.transform.GetChild(4).gameObject.transform.localScale = originalPiece.transform.lossyScale * 49;
                clone.transform.GetChild(5).gameObject.transform.localScale = originalPiece.transform.lossyScale * 49;
                clone.transform.GetChild(6).gameObject.transform.localScale = originalPiece.transform.lossyScale * 49;
            }
            Debug.Log("start new elvel");
            
            highscoreTimer.timerStop = true;
            //StartCoroutine(LoadNewLevel());
            LoadNewLevel();


        }
        
    }

    void LoadNewLevel()
    {
        //yield return new WaitForSeconds(waitAfterHit);
        SceneManager.LoadScene(levelName);
    }

Any thoughts?

SceneManager was kinda built to be run asynchronously - as such, LoadLevel does some weird things with timing and it is recommended you use LoadLevelAsync in most cases. Because you are already calling this from a coroutine, it’s even more appropriate;

...
    Debug.Log("Score set!");
}
//LoadLevel();
if (levelToMoveToElseBlank != "")
{
    yield return SceneManager.LoadSceneAsync(SceneManager.GetActiveScene().buildIndex + 1); //go to next level once enemies are dead
}
else
{
...