GeezerVison is showing github.com — The asyncio REPL interactive daemon thread doesn't handle `PYTHONSTARTUP` exceptions · Issue #140287 · python/cpython
The asyncio REPL interactive daemon thread doesn't handle PYTHONSTARTUP exceptions #140287DescriptionBug report
Bug description:
That leads to flaky behaviors.
This is my PYTHONSTARTUP file:
raise ModuleNotFoundError("oops!")
ModuleNotFoundError is just an example exception that can occur in PYTHONSTARTUP scripts.
This is how the regular REPLs handle it (both the basic REPL and the new REPL):
❯ PYTHONSTARTUP=t.py ./python
Python 3.15.0a1+ (heads/main:fbf0843e39e, Oct 18 2025, 11:24:43) [GCC 15.2.1 20250808 (Red Hat 15.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
Traceback (most recent call last):
File "t.py", line 1, in <module>
raise ModuleNotFoundError("oops!")
ModuleNotFoundError: oops!
>>>
The traceback is shown and we proceed to the loop.
For the asyncio REPL, startup file exception always causes it to exit immediately -- we'd never want the REPL to exit because of a startup file error. On top of that, it doesn't report the exception properly, because it's racing with the interpreter shutdown at that point.
I've found 3 variants of the incorrect behavior:
-
The interactive daemon thread doesn't write the full traceback:
❯ PYTHONSTARTUP=t.py ./python -m asyncio
asyncio REPL 3.15.0a1+ (heads/main:fbf0843e39e, Oct 18 2025, 11:24:43) [GCC 15.2.1 20250808 (Red Hat 15.2.1-1)] on linux
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
Exception in thread Interactive thread:
exiting asyncio REPL...
Traceback (most recent call last):
-
The interactive daemon thread does flush, but after exiting is reported:
❯ PYTHONSTARTUP=t.py ./python -m asyncio
asyncio REPL 3.15.0a1+ (heads/main:fbf0843e39e, Oct 18 2025, 11:24:43) [GCC 15.2.1 20250808 (Red Hat 15.2.1-1)] on linux
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
Exception in thread Interactive thread:
exiting asyncio REPL...
Traceback (most recent call last):
File "/home/bswck/Python/cpython/Lib/threading.py", line 1075, in _bootstrap_inner
self._context.run(self.run)
~~~~~~~~~~~~~~~~~^^^^^^^^^^
File "/home/bswck/Python/cpython/Lib/asyncio/__main__.py", line 104, in run
exec(startup_code, console.locals)
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "t.py", line 1, in <module>
raise ModuleNotFoundError("oops!")
ModuleNotFoundError: oops!
-
The interactive daemon tries to acquire stderr at interpreter shutdown, and fails:
❯ PYTHONSTARTUP=t.py ./python -m asyncio
asyncio REPL 3.15.0a1+ (heads/main:fbf0843e39e, Oct 18 2025, 11:24:43) [GCC 15.2.1 20250808 (Red Hat 15.2.1-1)] on linux
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
Exception in thread Interactive thread:
exiting asyncio REPL...
Traceback (most recent call last):
File "/home/bswck/Python/cpython/Lib/threading.py", line 1075, in _bootstrap_inner
self._context.run(self.run)
~~~~~~~~~~~~~~~~~^^^^^^^^^^
Fatal Python error: _enter_buffered_busy: could not acquire lock for <_io.BufferedWriter name='<stderr>'> at interpreter shutdown, possibly due to daemon threads
Python runtime state: finalizing (tstate=0x00000000009c3818)
Current thread 0x00007f6c4781cbc0 [python] (most recent call first):
<no Python frame>
Aborted (core dumped)
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
Activityjohnslavik commented on Oct 18, 2025 CC @ZeroIntensity (mentorship) I'd add these labels: stdlib, type-repl, type-asyncio. Perhaps also version labels once I reproduce for all versions. johnslavik commented on Oct 18, 2025 The simplest fix is to just handle these exceptions with sys.excepthook (via console.showtraceback). johnslavik commented on Oct 18, 2025 Interestingly, _pyrepl doesn't seem to properly handle this as well when pythonstartup=True is passed to _pyrepl.main.interactive_console. PYTHONSTARTUP=t.py ./python -c 'import _pyrepl.main; _pyrepl.main.interactive_console(pythonstartup=True)' exits immediately. However, it doesn't suffer from problems that daemonic threads do. I need to check that later. johnslavik commented on Nov 8, 2025 This is a bugfix -- let's add 3.13, 3.14 and 3.15 here cc @ZeroIntensity mentorship added a commit that references this issue on Apr 25, 2026gh-140287: Handle `PYTHONSTARTUP` script exceptions in the asyncio RE…
MetadataMetadataStatusShow more project fields
DevelopmentNo branches or pull requestsIssue actions
|