Skip to content

asyncio.run_coroutine_threadsafe drops specified exceptions' traceback #117459

Closed
@rsp4jack

Description

@rsp4jack

Bug report

Bug description:

import asyncio import threading import traceback async def raiseme(): raise ValueError(42) async def raiseme2(): raise asyncio.TimeoutError() loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) thr = threading.Thread(target=loop.run_forever, daemon=True) thr.start() print('raiseme() run_coroutine_threadsafe') try: task = asyncio.run_coroutine_threadsafe(raiseme(), loop) task.result() except: traceback.print_exc() print('raiseme2() run_coroutine_threadsafe') try: task = asyncio.run_coroutine_threadsafe(raiseme2(), loop) task.result() except: traceback.print_exc()
raiseme() run_coroutine_threadsafe Traceback (most recent call last): File "g:\Projects\NowPlaying\test.py", line 18, in <module> task.result() File "C:\Program Files\Python312\Lib\concurrent\futures\_base.py", line 456, in result return self.__get_result() ^^^^^^^^^^^^^^^^^^^ File "C:\Program Files\Python312\Lib\concurrent\futures\_base.py", line 401, in __get_result raise self._exception File "g:\Projects\NowPlaying\test.py", line 6, in raiseme raise ValueError(42) ValueError: 42 raiseme2() run_coroutine_threadsafe Traceback (most recent call last): File "g:\Projects\NowPlaying\test.py", line 25, in <module> task.result() File "C:\Program Files\Python312\Lib\concurrent\futures\_base.py", line 456, in result return self.__get_result() ^^^^^^^^^^^^^^^^^^^ File "C:\Program Files\Python312\Lib\concurrent\futures\_base.py", line 401, in __get_result raise self._exception TimeoutError 

The traceback of the second exception (TimeoutError) is dropeed.

The reason is that _convert_future_exc drops the origin exception's traceback:

def _convert_future_exc(exc):
exc_class = type(exc)
if exc_class is concurrent.futures.CancelledError:
return exceptions.CancelledError(*exc.args)
elif exc_class is concurrent.futures.TimeoutError:
return exceptions.TimeoutError(*exc.args)
elif exc_class is concurrent.futures.InvalidStateError:
return exceptions.InvalidStateError(*exc.args)
else:
return exc

To fix it, construct the new exception with the original traceback like that:

return exceptions.CancelledError(*exc.args).with_traceback(exc.__traceback__)

CPython versions tested on:

3.10, CPython main branch

Operating systems tested on:

Linux, Windows

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions