Description
This issue is to discuss if and how to document "stored exceptions", that is, exceptions that are stored in the returned object by Task-returning methods.
With async methods, and more generally Task-returning methods, a majority of exceptions don't emerge synchronously from the call. Rather, any exception gets stored into the returned Task, and then later asking that Task for the exception (via await'ing it, .Wait()'ing it, accessing its .Exception), etc., will surface the exception. If you have a method:
public static async Task MethodAsync()
{
await Task.Yield();
throw new FormatException();
}
and you call it as:
Task t = MethodAsync();
the call to MethodAsync will never throw a FormatException
. Rather, such an exception may emerge when you later await the task, e.g.
await t; // throws FormatException
t.GetResult().GetAwaiter(); // throws FormatException
t.Wait(); // throws an AggregateException wrapping FormatException
Exception e = Task.Exception; // returns an AggregateException wrapping FormatException
...
Historically, then, we haven't documented FormatException as an exception thrown out of MethodAsync, because technically it's not. Of course, in the 95% use case where a developer does:
await MethodAsync();
the distinction is irrelevant, as it's not directly observable whether the exception was thrown from MethodAsync or by awaiting the task it returned.
Originally posted by @stephentoub in #7692 (comment)