Description
When the user sends an interrupt message while Hermes CLI is executing a long-running task, the process crashes with OSError: [Errno 5] Input/output error during prompt_toolkit shutdown.
Reproduction
- Start a long-running task in Hermes CLI
- Send an interrupt message (press Enter with busy_input_mode=interrupt)
- Observe: process crashes and restarts
Error Log
OSError: [Errno 5] Input/output error
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File ".../prompt_toolkit/renderer.py", line 429, in reset
self.output.flush()
File ".../prompt_toolkit/output/vt100.py", line 706, in flush
flush_stdout(self.stdout, data)
File ".../prompt_toolkit/output/flush_stdout.py", line 37, in flush_stdout
stdout.flush()
OSError: [Errno 5] Input/output error
Root Cause Analysis
Two issues compound:
-
Signal handler raises KeyboardInterrupt at arbitrary C stack point (cli.py:9682): The _signal_handler raises KeyboardInterrupt inside a Unix signal handler. This causes prompt_toolkit to attempt emergency shutdown, which tries to flush stdout that is in a broken/devnull state.
-
OSError with errno 5 not suppressed (cli.py:9699-9706): The _suppress_closed_loop_errors exception handler only suppresses:
RuntimeError: "Event loop is closed"
KeyError: "is not registered"
But OSError: [Errno 5] Input/output error from stdout flush falls through to the default handler, which then crashes the process.
Additional Context from interrupt_debug.log
05:31:21 interrupt fired: msg=..., agent_running=True
05:45:43 ... OSError: [Errno 5] Input/output error (crash + restart)
05:55:42 interrupt fired: msg=..., agent_running=True
06:00:09 ... OSError: [Errno 5] Input/output error (crash + restart)
Environment
- macOS Darwin 25.4.0 (Apple Silicon M3)
- Python 3.9.6 via uv
- Hermes Agent latest (NousResearch/hermes-agent)
- busy_input_mode: interrupt
Expected Behavior
Hermes CLI should gracefully handle interrupts without crashing.
Suggested Fix
- Add
OSError with errno 5 (Input/output error) to _suppress_closed_loop_errors
- Alternatively, change signal handler to use a flag-based approach instead of raising an exception
Description
When the user sends an interrupt message while Hermes CLI is executing a long-running task, the process crashes with
OSError: [Errno 5] Input/output errorduring prompt_toolkit shutdown.Reproduction
Error Log
Root Cause Analysis
Two issues compound:
Signal handler raises KeyboardInterrupt at arbitrary C stack point (cli.py:9682): The
_signal_handlerraisesKeyboardInterruptinside a Unix signal handler. This causes prompt_toolkit to attempt emergency shutdown, which tries to flush stdout that is in a broken/devnull state.OSError with errno 5 not suppressed (cli.py:9699-9706): The
_suppress_closed_loop_errorsexception handler only suppresses:RuntimeError: "Event loop is closed"KeyError: "is not registered"But
OSError: [Errno 5] Input/output errorfrom stdout flush falls through to the default handler, which then crashes the process.Additional Context from interrupt_debug.log
Environment
Expected Behavior
Hermes CLI should gracefully handle interrupts without crashing.
Suggested Fix
OSErrorwith errno 5 (Input/output error) to_suppress_closed_loop_errors