question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Exceptions are never reported when UniTask is executed without await and Forget()

See original GitHub issue

An exception that happens inside a UniTask is never reported, not even after GC.Collect, under specific conditions:

  • the UniTask method is run without await and Forget()
  • the exception is thrown in the same frame the UniTask is launched

An example:

public class TestBehaviour : MonoBehaviour
{
    private void Awake()
    {
        TestAsync();
    }

    private async UniTask TestAsync()
    {
        throw new Exception();
    }
}

The exception will not be logged to the console even if I press GC.Collect in the UniTask Tracker window. However, if the exception is thrown in subsequent frames, everything is fine:

private async UniTask TestAsync()
{
    await UniTask.NextFrame();
    throw new Exception(); // logged after GC.Collect
}

The bug is unlikely to happen because usually there is a CS4014 warning that warns us the call is not awaited. However, when using async methods through interfaces, the warning is not reported, so you can forget to use either await or Forget():

public interface ITestInterface
{
    UniTask Test();
}

public class TestClass : ITestInterface
{
    public async UniTask Test()
    {
        throw new Exception();
    }
}

public class TestBehaviour : MonoBehaviour
{
    private void Awake()
    {
        ITestInterface interfaceInstance = new TestClass();
        interfaceInstance.Test(); // There is no CS4014 warning because there is no async keyword in the interface declaration.
    }
}

So when you forget to put await or Forget() in such a case, it is a very big pain to debug it later because there is no sign of what went wrong.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:2
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

4reactions
neuecccommented, Oct 15, 2021

Thanks. You are correct, I’m sorry to didn’t investigate. It would be better to change the Exception ex; field to ExceptionHolder.

1reaction
SolidAlloycommented, Sep 9, 2021

Destroying TestBehaviour doesn’t help, unfortunately, not even destroying the game object it is in

Read more comments on GitHub >

github_iconTop Results From Across the Web

Async Tasks, Cancellation, and Exceptions
Just without the exception. I always get a TaskCanceledException if I await the task returned. My guess would be that this is normal...
Read more >
Suppressing/not logging exceptions from ThreadPool and ...
As you can see there are three exceptions thrown from background threads. From newly created thread and from thread pool. In "normal" ....
Read more >
com.cysharp.unitask
Provides an efficient allocation free async/await integration for Unity. Struct based UniTask<T> and custom AsyncMethodBuilder to achieve zero allocation; Makes ...
Read more >
Unity Async vs Coroutine
The time it takes to run UniTask.Yield() matches the coroutine and async counterparts. No alt text provided for this image. Here's where it...
Read more >
Async in Unity (better or worse than coroutines?)
Async / Await is a C# scripting feature in Unity that allows you to execute part of a function asynchronously.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found