yield return StartCoroutine and StopCoroutine weird behaviour

Hi,

Consider the following code:

        private Coroutine stopMeRoutine;
        private void Start()
        {
            StartCoroutine(Test());
        }
       
        IEnumerator Test()
        {
            while (true)
            {
                stopMeRoutine = StartCoroutine(StopMe());
                yield return stopMeRoutine;
                Debug.Log("Next!");
            }
        }

        IEnumerator StopMe()
        {
            while (true)
            {
                Debug.Log("Running...");
                yield return new WaitForSeconds(1);
            }
        }

        private void Update()
        {
            if (Input.GetMouseButtonDown(0))
            {
                Debug.Log("Stopping!");
                StopCoroutine(stopMeRoutine);
            }
        }

I would expect “Next!” to be logged after a click, however, Test() hangs indefinitely after a click.
Seems like yield return stopMeRoutine never knows about the coroutine being stopped externally, which is weird because they are the same coroutine instance.

Is this expected behaviour? Any ways around this?

This is indeed the behavior. I guess stopping a coroutine is seen as aborting it and, since any coroutines waiting on it have no means of knowing if the routine has completed or was aborted, it was deemed safer to never continue those routines.

You’ll have to use another way to gracefully stop the inner coroutine, you could use while (someField) { } and set the field to false, pass in a Func<bool> delegate that returns false based on some custom condition or even use CancellationToken, which is the canonical way to stop async/await tasks.