Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I catch an exception from async code?

Tags:

c#

.net

c#-5.0

Everywhere I read it says the following code should work, but it doesn't.

public async Task DoSomething(int x)
{
   try
   {
      // Asynchronous implementation.
      await Task.Run(() => {
      throw new Exception();
      x++;
      });
   }
   catch (Exception ex)
   {
      // Handle exceptions ?
   }
}

That said, I'm not catching anything and get an "unhandled exception" originating at the 'throw' line. I'm clueless here.

like image 816
Dror Weiss Avatar asked Nov 08 '13 17:11

Dror Weiss


People also ask

How do I catch exceptions with async await?

catch (in combination with async functions) and the . catch() approaches to handle errors for asynchronous code. When returning a promise within a try block, make sure to await it if you want the try... catch block to catch the error.

Does await throw exception?

When you await a Task, the first exception is re-thrown, so you can catch the specific exception type (such as InvalidOperationException). However, when you synchronously block on a Task using Task. Wait or Task. Result, all of the exceptions are wrapped in an AggregateException and thrown.

What happens when async method is not awaited?

The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.

Is it possible to catch an exception thrown by async method?

Using the async CTP from Microsoft for .NET, is it possible to catch an exception thrown by an async method in the calling method? public async void Foo () { var x = await DoSomethingAsync (); /* Handle the result, but sometimes an exception might be thrown.

Why asynchronous exception is uncatchable in Java?

Asynchronous exception is uncatchable because the intended catch block is not present when the asynchronous code is executed. Instead, the exception will propagate all the way and terminate the program.

What are the best practices in async/await?

As Stephen Cleary wrote in Async/Await - Best Practices in Asynchronous Programming: Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async Task method, that exception is captured and placed on the Task object.

What is the difference between async async void and async task?

Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async Task method, that exception is captured and placed on the Task object.


3 Answers

You have the "Just my code" Option turned on. With this on, it is considering the exception unhandled with respect to "just your code"--because other code is catching the exception and stuffing it inside of a Task, later to be rethrown at the await call and caught by your catch statement.

Without being attached in the debugger, your catch statement will be triggered, and it will run as you expect. Or you can just continue from within the debugger and it will run as expected.

The better thing to do is to just turn off "Just my code". IMO, it causes more confusion than it is worth.

like image 184
Matt Smith Avatar answered Oct 02 '22 12:10

Matt Smith


As SLaks said, your code works fine.

I strongly suspect you over-simplified your example, and have an async void in your code.

The following works fine:

private static void Main(string[] args) {     CallAsync();     Console.Read(); }  public static async void CallAsync() {     try     {         await DoSomething();     }     catch (Exception)     {         // Handle exceptions ?         Console.WriteLine("In the catch");     } }  public static Task DoSomething() {     return Task.Run(() =>     {         throw new Exception();     }); } 

The following doesn't work:

private static void Main(string[] args) {     CallAsync();     Console.Read(); }  public static void CallAsync() {     try     {         DoSomething();     }     catch (Exception)     {         // Handle exceptions ?         Console.WriteLine("In the catch");     } }  public static async void DoSomething() {     await Task.Run(() =>     {         throw new Exception();     }); } 

See http://msdn.microsoft.com/en-us/magazine/jj991977.aspx

Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async Task method, that exception is captured and placed on the Task object. With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on the SynchronizationContext that was active when the async void method started. Figure 2 illustrates that exceptions thrown from async void methods can’t be caught naturally.

like image 39
ken2k Avatar answered Oct 02 '22 12:10

ken2k


Your code won't even compile cleanly at the moment, as the x++; statement is unreachable. Always pay attention to warnings.

However, after fixing that, it works fine:

using System;
using System.Threading.Tasks;

class Test
{
    static void Main(string[] args)
    {
        DoSomething(10).Wait();
    }

    public static async Task DoSomething(int x)
    {
        try
        {
            // Asynchronous implementation.
            await Task.Run(() => {
                throw new Exception("Bang!");
            });
        }
        catch (Exception ex)
        {
            Console.WriteLine("I caught an exception! {0}", ex.Message);
        }
    }
}

Output:

I caught an exception! Bang!

(Note that if you try the above code in a WinForms app, you'll have a deadlock because you'd be waiting on a task which needed to get back to the UI thread. We're okay in a console app as the task will resume on a threadpool thread.)

I suspect the problem is actually just a matter of debugging - the debugger may consider it unhandled, even though it is handled.

like image 32
Jon Skeet Avatar answered Oct 02 '22 13:10

Jon Skeet