Unity Awaitables - Catching swallowed exceptions

How to catch Awaitable swallowed exceptions.

Unity Awaitables - Catching swallowed exceptions
Photo by Mahdi Bafande / Unsplash

If you're working with Awaitables in Unity, you may stumped upon the fact that if you run an Awaitable without awaiting, all exceptions are swallowed, e.g.:

private async Awaitable DoSomething()
{
  // your code.
}

private void Start()
{
  _ = DoSomething();
}

This is a typical pattern for starting asynchronous work without waiting for the result. In this case, if DoSomething throws, the exception will be swallowed silently. This is not a unique Unity behavior but how Tasks in C# work.

Now, if you want to get the swallowed exceptions, you can use this extension method:

public static class AwaitableExtensions
{
  public static void Forget(this Awaitable awaitable)
  {
    var awaiter = awaitable.GetAwaiter();
    
    if (awaitable.IsCompleted)
    {
      try
      {
        awaiter.GetResult();
      }
      catch (Exception ex) when (ex is OperationCanceledException)
      {
        // Silently swallow OperationCanceledExceptions since this is expected.
        // Everything else will throw.
      }
    }
    else
    {
      awaiter.OnCompleted(() =>
      {
        try
        {
          awaiter.GetResult();
        }
        catch (Exception ex) when (ex is OperationCanceledException)
        {
          // Silently swallow OperationCanceledExceptions since this is expected.
          // Everything else will throw.
        }
      });
    }
  }
}

And then call your Awaitable like this:

private void Start()
{
  DoSomething().Forget();
}

Now, any error will show up in the console as usual.

If you're using UniTask, you also want to use its Forget() method when you're not going to await a UniTask which basically is doing the same to catch any exception.