Task.Exception exposes the failure associated with a faulted Task or Task<T>. After completion, inspect IsFaulted, then read Exception without throwing; the property contains an AggregateException. section 3.2.4
AggregateException can contain several failures because one Task may represent parallel operations. Its InnerExceptions collection holds the original exceptions; do not substitute InnerException, which is not the relevant property here. section 3.2.4 section 12.2
Choose the access pattern according to whether you need inspection or propagation:
- Inspect without throwing: wait for completion, test IsFaulted, and handle task.Exception. section 3.2.4
- Propagate after completion: call Wait; it returns immediately for a completed task or throws for cancellation or failure. section 3.2.4
- Use await when ordinary exception handling is preferred; await unwraps the AggregateException and throws its first inner exception, potentially discarding additional failures. section 12.2
- When collecting tasks without await, handle both exceptions thrown before the asynchronous operation returns and exceptions later stored in Task.Exception. section 12.1
Inspecting a stored failure
var tcs = new TaskCompletionSource(); tcs.SetException(new NotSupportedException()); if (tcs.Task.IsFaulted) { AggregateException error = tcs.Task.Exception; HandleError(error.InnerExceptions[0]); } await tcs.Task; // throws NotSupportedException, not AggregateException section 12.2 section 3.2.4
if(task.IsFaulted) HandleError(task.Exception);
Use the compact status-check pattern when you need to inspect a completed task without immediately rethrowing its failure. section 3.2.4
An async void method has no Task.Exception for its caller to inspect. Restrict async void to event handlers and catch exceptions inside those handlers. section 3.4
