Coroutines dying in 5.6?

I updated my Unity app to 5.6.0f3 and I’m seeing some coroutines just die. As in, they do a “yield return new WaitForSeconds()” or “yield return null” and then the next line never executes. I’m 100% sure that the object running the coroutine is not being destroyed or deactivated, that StopCoroutine or StopAllCoroutines is not being called, and that I’m also passing a reasonable number of seconds into WaitForSeconds.

I haven’t quite nailed down a repro yet, but I’m wondering if anyone else has seen this problem or might know more information. I’ve seen it in the editor, standalone Windows builds, and in WebGL builds, and seen it happen in different coroutines throughout in my app.

When it happens it only happens once, and then everything works fine again until I restart the app. Strangely, it also doesn’t seem tied to the first coroutine my app runs, and instead picks some random time to happen.

I even tried downgrading to 5.5 for a bit and saw the problem go away, and re-upgraded to 5.6 and saw it come back. So I’m pretty sure something is up with 5.6.

I think there is something buggy with the coroutine structure in Unity 5.6. My coroutines are experiencing problems too with the 5.6 update. I hope this problem has already been discovered by the Unity team. If you figured out something could you please share? Thanks!

Please give more information, it’s not a widely known issue as far as I can see… example possible?

Unfortunately I was never able to nail down what caused it. It must be conflicting somewhere with something else my app is doing, but I can’t for the life of me figure what that would be.

I did some make some progress tracking it. I found a reliable repro, and kept commenting out big sections of my app until the repro went away. Doing this for several hours narrowed it down to two image objects I was inserting into a dialog. If I commented out both of those images, coroutines worked fine.

The code causing the issue narrowed down to simply “new GameObject(”…“).AddComponent()”. I realized that these objects were being inserted into a canvas with normal Transforms instead of RectTransform. Changing them to RectTransforms fixed it! “new GameObject(”…“, typeof(RectTransform)).AddComponent()”

So I added some asserts and checks to my app to ensure that I was always ensuring I only ever add RectTransform objects to my canvases. I found a few other places where I had forgotten to do this. After fixing all of these, the coroutine problem happened… less often. But it still happens. And now I can’t reliably repro it.

In the end I had spent way too much time on this issue, so I ended up just writing my own coroutine system and stopped using Unity’s. It was actually pretty easy to write once I thought it through. This has worked around the problem for me.

It would be really nice if there was a way to debug it. I want a way to say “tell me all coroutines that are active on this MonoBehaviour, and what it’s waiting on.” I want to see if the coroutine is really deleted, or if it’s still in memory on Unity’s side and blocked on something. But Unity does not expose this information anywhere as far as I can tell, even in the editor.

1 Like

I’ve been scripting a few coroutines in 5.6 over the last few days and I haven’t noticed any ‘non-completion’ problems. I appreciate the fact that your coroutines work in 5.5, but have you considered adding a conditional boolean to force completion ?. At very least it may help to shed some light on the issue.

Example

using UnityEngine;
using System.Collections;

public class RoutineTest : MonoBehaviour {
    private bool routineActive;

    // --
    void Update () {
        if (!routineActive && Input.GetKeyDown (KeyCode.Z)) {
            StartCoroutine (TargetCoroutine ());
        }
    }
    // --
    private IEnumerator TargetCoroutine () {
        routineActive = true;
        //
        // ** Code **
        //
        yield return new WaitForSeconds (2.0f);
        routineActive = false;
    }
}

At the moment I am not able to reproduce the effect exactly to find out what is causing it. The conditional boolean is a good way to test it. I’ll try to nail the cause adn answer with more information. Thank you all for the info.

Yes, I’ve added flags like what you suggest to watch. And what I see happening is that, the line after “yield return new WaitForSeconds” is never called. I could leave the app open for an hour, but the routineActive variable would stay true forever.

I’ve also added Debug.Log statements before and after the “yield return new WaitForSeconds” and what I see is that, when this happens, the before one gets called, but the after one never does.

I should also mention, no errors or warnings are in the console, and I’m 100% sure that no exceptions are being thrown (there’s no try/catch or anything like that)

Thanks for the suggestion!

Try attaching the following ‘TargetRoutine’ script to an empty game object. It’s working as expected here.

TargetRoutine Script

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class TargetRoutine : MonoBehaviour {
    public List<string> testList;
    public bool routineActive;

    // --
    void Awake () {
        testList = new List<string> ();
    }
    // --
    void Start () {
        PopulateTestList ();
    }
    // --
    void Update () {
        if (!routineActive && Input.GetKeyDown (KeyCode.Z)) {
            StartCoroutine (targetRoutine ());
        }
    }
    // --
    void PopulateTestList () {
        for (int i = 0; i < 10; i++) {
            testList.Add ("Item " + i);
        }
    }
    // --
    private IEnumerator targetRoutine() {
        routineActive = true;
        //
        Debug.Log ("Start Coroutine");
        //
        foreach (string item in testList) {
            Debug.Log (item);
            yield return new WaitForSeconds (0.25f);
        }
        Debug.Log ("End Coroutine");
        routineActive = false;
    }
}

if I execute my code like this, everything works again, but it definitely looks like a bug to me.

A co routine does not seem to be executed anymore as soon as it passed any yield return statements.

I tested the code directly above this post and works fine to me. This is expected behaviour. I get End Coroutine message when it is finished.

Do you have any code relating to Time class?

If someone could upload an example script (one that fails to complete), I’d be happy to test it on my system.

I tested a bit more and narrowed it down to my coroutines not working if I add them on anything that is directly on a canvas, if I attach them to another gameobject it does work fine.

public class TestTester : MonoBehaviour {

// Use this for initialization
void Start () {
StartCoroutine(HurpDurp());
}

private IEnumerator HurpDurp()
{

while (true)
{
Debug.Log(“HurperDurper”);
yield return null;
}
}

// Update is called once per frame
void Update () {

}
}

this code works on a regular gameobject in my scene, if I attach it to my canvas or a gameobject in a canvas, it stops executing the first time it reaches the yield return statement

Probably best you file a bug report (help menu->etc) and attach your example so Unity can reproduce if you think it’s an issue. It’s just not an issue I can find.

I’ve tested your script attached to a canvas button with the following result…

For what it’s worth I’ve got this issue as well. At first I thought I was going crazy, but it appears to be somewhat random and intermittent. It absolutely has something to do with yielding, though, as you can set a break point before a yield, and after a yield, and the before-yield will break correctly, but the after-yield break will never be hit. I’m not sure if the coroutine itself is dying, or if the yield is somehow never returning – either way sometimes you’ll get a crazy yield-of-death that stops a coroutine (or coroutines) dead and there’s no way to detect it or recover.

It’s definitely a 5.6 issue, as I have completely unchanged code that worked great in 5.5 that no longer works in 5.6. Given its random nature, I’m having a real tough time finding a reliable repro case. In my case, it’s got nothing to do with UI or Canvases (at least, it hasn’t affected my UI yet), so I don’t think it’s related solely to coroutines and UI.

I’m pretty much at a loss here. Thankfully I found this thread as I was getting crazy debug results and was getting increasingly confused. If anyone’s got any ideas I’m game for a bit of debugging, but after spending most of today on this I can’t seem to find a rhyme or reason to this, aside from being as certain as I can be that this happens on yields (WaitForSeconds seems to trigger this the most frequently). Really strange, but also super frustrating!

1 Like

I’ve been unable to reproduce the issue so it’s hard to track down the culprit, but I’d like someone to navigate to Edit / Project Settings / Time and check that Time Scale is not set to zero

You could also try adding the following to the script…

void Awake () {
Time.timeScale = 1.0f;
}

This will at very least eliminate a time scale issue

We have the same problem in our projects. We have been testing, and we have arrived at the conclusion that the problem is due to the coexistence of an active canvas and coroutines in a same script.

If we activate a canvas before the start of the coroutine, and do nothing else inside except waiting for 0.5 seconds, the execution fails. An example of the coroutine is the next:

private IEnumerator Test()
{
     while (true)
     {
          Debug.Log("Testing...");
          yield return new WaitForSeconds(0.5f);
     }
}

But as long as we didn’t touch the canvas, execution seemed fine.

Another test was adding a public variable with a canvas attached, and trying three things with the state of the canvas:

  • Canvas deactivated and then start the coroutine: Everything is fine.
  • Canvas activated and then start the coroutine: Not working.
  • Canvas deactivated and then start the coroutine, activating the canvas after a few seconds: Working only as long as the canvas is not active.

I can rule this out on my end. I double-checked that Time Scale wasn’t zero in the inspector and I even set it in my start-up script (setting it straight to 1, and also setting it to 0 and then 1 just in case) and it didn’t make a difference. Coroutines still randomly break.

I’m still not sure about the UI thing, as I’m having Coroutines break on standard MonoBehaviours that have no references to any UI stuff. UI exists in the scene, but even if that’s disabled or removed Coroutines still randomly break.

I’ve done a little bit of extra digging, so here’s where I’m at right now:

I created this class:

using UnityEngine;

/// <summary>
/// Suspends the coroutine execution for the given amount of seconds.
/// </summary>
public class WaitForSeconds : CustomYieldInstruction
{
    private float waitTime;

    public override bool keepWaiting
    {
        get { return Time.time < waitTime; }
    }

    public WaitForSeconds(float time)
    {
        waitTime = Time.time + time;
    }
}

Which basically hides the default WaitForSeconds and allows me to set a breakpoint inside the keepWaiting property. While watching the Time.time < waitTime, I discovered that it indeed looks like the Coroutine is being killed, or dying. The behaviour I’m seeing is:

  • The keepWaiting breakpoint is being hit correctly. It’s waiting for the statement to be false.
  • Eventually, after a few hits but before the statement finishes (i.e. evaluates to false) the breakpoint stops being hit.
  • The only conclusion I can make from this is that after a while (when the yield gets close to completing) something happens that stops the evaluation dead. keepWaiting is no longer checked, even though the statement never evaluated to false (which means the IEnumerator never continues).

At this point I’m pretty sure this is a bug. I’m thinking that the only thing to do is to roll back to 5.5, as something seems to be fundamentally wrong with the way 5.6 handles IEnumerators and yielding. I wish there was more I could do in terms of making this reproducible, but as far as I can tell this is completely random. Once it starts happening, though, I can’t find a way to track it down or get rid of it.

I have the same problem with my project here I am going to file a bug report. Hopefully they will fix it soon.