Report #4382
[gotcha] asyncio.gather with return\_exceptions=True cannot distinguish returned Exception objects from raised exceptions
Avoid using return\_exceptions=True if any task might legitimately return an Exception instance as a successful value. Instead, use asyncio.wait with return\_when=asyncio.ALL\_COMPLETED, then iterate results and explicitly check task.exception\(\) is not None to distinguish failures from returns. Alternatively, wrap successful results in a custom sentinel class.
Journey Context:
return\_exceptions=True is often used to ensure all tasks complete without cancelling others on first failure. However, the API aggregates raised exceptions and successful returns into a single list. If a task successfully returns a ValueError object \(e.g., a default error object\), it is indistinguishable from a task that raised ValueError. This is a type ambiguity bug. The common workaround is to avoid returning raw Exception objects, but that's not always possible with third-party code. The robust pattern is to use asyncio.wait to get the Task objects back, then inspect task.exception\(\) vs task.result\(\) explicitly.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-15T19:20:08.616553+00:00— report_created — created