Why can't I catch an exception from async code?
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.
Exception thrown in async method is not caught - why?
As described for example in this blog post by Stephen Cleary - the state machine for
async
methods will capture exceptions from your code and place them on the returned task, i.e. method invocation will not throw, you will be able to catch exception ifawait
the result.As for
TaskScheduler.UnobservedTaskException
- check out this answer and be sure to run code inRelease
mode.
Why I couldn't catch the exception in async function that has void return type?
Any time you have async void
, you're basically breaking the ability to correctly signal completion and failure; the only way it can report failure is if the exception happens immediately and before any incomplete await
- i.e. synchronously. In your case, the Task.Run
guarantees that this is not synchronous, hence any knowledge of the outcome and failure: is lost.
Fundamentally, never write async void
(unless you absolutely have to, for example in an event-handler). In addition to the problem above, it also has known complications with some SynchronizationContext
implementations (in particular the legacy ASP.NET one), which means simply invoking an async void
method is enough to crash your application (at least hypothetically; the sync-context caveat applies more to library authors than application authors, since library authors don't get to choose the application execution environment).
Remove the async void
. If you want to return "nothing", then you should use async Task
or async ValueTask
as the signature:
static async Task MyMethodAsync() {
await TestThrowException();
}
(which could perhaps also be simplified to)
static Task MyMethodAsync()
=> TestThrowException();
and:
static async Task Main(string[] args) {
try {
await MyMethodAsync();
}
catch (Exception e) {
Console.WriteLine("Catch");
}
Console.ReadLine();
}
Why is try {} .. catch() not working with async/await function?
You need to await errorTest
const callFunction=async()=>{
try{
const result = await errorTest()
}catch(err){
console.log(err)
}
}
callFunction ()
Note that the await errorTest() function has to also be in an async function. That's why I put it inside callFunction ()
Another Option
const errorTest = async() => {
try{
const result = await $.get("http://dataa.fixer.io/api/latest?access_key=9790286e305d82fbde77cc1948cf847c&format=1");
console.log(result)
}catch(err){
console.log(err)
}
}
Catching Exceptions in async methods when not called with await
exception was thrown before an await was done, that it would execute synchronously
Thought this is fairly true, but it doesn't mean you could catch the exception.
Because your code has async
keyword, which turns the method into an async state machine i.e. encapsulated / wrapped by a special type. Any exception thrown from async state machine will get caught and re-thrown when the task is await
ed (except for those async void
ones) or they go unobserved, which can be caught in TaskScheduler.UnobservedTaskException
event.
If you remove async
keyword from the NonAwaitedMethod
method, you can catch the exception.
A good way to observe this behavior is using this:
try
{
NonAwaitedMethod();
// You will still see this message in your console despite exception
// being thrown from the above method synchronously, because the method
// has been encapsulated into an async state machine by compiler.
Console.WriteLine("Method Called");
}
catch (Exception e)
{
Console.WriteLine("Exception Caught");
}
So your code is compiled similarly to this:
try
{
var stateMachine = new AsyncStateMachine(() =>
{
try
{
NonAwaitedMethod();
}
catch (Exception ex)
{
stateMachine.Exception = ex;
}
});
// This does not throw exception
stateMachine.Run();
}
catch (Exception e)
{
Console.WriteLine("Exception Caught");
}
why does swapping from Task to void return type cause the exception to get caught
If the method returns a Task
, the exception is caught by the task.
If the method is void
, then the exception gets re-thrown from an arbitrary thread pool thread. Any unhandled exception thrown from thread pool thread will cause the app to crash, so chances are the debugger (or maybe the JIT debugger) is watching this sort of exceptions.
If you want to fire and forget but properly handle the exception, you could use ContinueWith
to create a continuation for the task:
NonAwaitedMethod()
.ContinueWith(task => task.Exception, TaskContinuationOptions.OnlyOnFaulted);
Note you have to visit task.Exception
property to make the exception observed, otherwise, task scheduler still will receive UnobservedTaskException
event.
Or if the exception needs to be caught and processed in Main
, the correct way to do that is using async Main methods.
Surprising case where exception handling in async method does not catch the exception
I don't understand the inconsistency in the second row of the table
The right side case (no state machines at all) is trivial:
- you call a method inside a
try/catch
block - the method throws an exception
- your
catch
black catches it - nothing special
The left side is actually easy to understand, too:
- you call a method inside a
try/catch
block - but this method is not what it seems, it has been converted to a state
machine, so what it returns is aTask
that represents the execution of the method's content as you implemented it(1) - so as long as you don't
Wait
orawait
that returnedTask
or try to access itsResult
property, the exception is not (re-)thrown inside yourtry
block.
(1) I wish my English was better to find a better and more exact description. As Servy pointed out, in your example an already faulted Task
is returned.
Exception in async methods is not caught
In your first example the exception is not caught because it does not occure before leaving the try/catch
block. If you want to catch it there you need to wait/await
it there exactly like you do in the second example.
If you do not await the returned task the method continues execution and leaves the try/catch
block before the exception actually occures...
If you want to catch the exception "out of band" you can also register to TaskScheduler.UnobservedTaskException
(this event is called if a task is throwing an exception which is nowhere caught) to get all uncaught exceptions or monitor the tasks Exception
property. May also check out THIS answer.
Catch an exception thrown by an async void method
It's somewhat weird to read but yes, the exception will bubble up to the calling code - but only if you await
or Wait()
the call to Foo
.
public async Task Foo()
{
var x = await DoSomethingAsync();
}
public async void DoFoo()
{
try
{
await Foo();
}
catch (ProtocolException ex)
{
// The exception will be caught because you've awaited
// the call in an async method.
}
}
//or//
public void DoFoo()
{
try
{
Foo().Wait();
}
catch (ProtocolException ex)
{
/* The exception will be caught because you've
waited for the completion of the call. */
}
}
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. 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.
Note that using Wait()
may cause your application to block, if .NET decides to execute your method synchronously.
This explanation http://www.interact-sw.co.uk/iangblog/2010/11/01/csharp5-async-exceptions is pretty good - it discusses the steps the compiler takes to achieve this magic.
Related Topics
C#:Is Variance (Covariance/Contravariance) Another Word for Polymorphism
How to Install a Certificate into the Local MAChine Store Programmatically Using C#
How to Catch SQLserver Timeout Exceptions
C# Iterating Through an Enum? (Indexing a System.Array)
How to Correctly Prefix a Word with "A" and "An"
Convert File Path to a File Uri
Why Does Path.Combine Not Properly Concatenate Filenames That Start with Path.Directoryseparatorchar
How to Check If Variable's Type Matches Type Stored in a Variable
How to Implement Recaptcha for ASP.NET MVC
Adding Headers When Using Httpclient.Getasync
Is Nameof() Evaluated at Compile-Time
C# an Established Connection Was Aborted by the Software in Your Host MAChine
Formatting a Double to Two Decimal Places
How to Set Value for Property of an Anonymous Object
Calling Oracle Stored Procedure from C#