Skip to content

fix(cli): PipeInput fallback when kqueue rejects stdin fd#9996

Closed
sougannkyou wants to merge 1 commit into
NousResearch:mainfrom
sougannkyou:fix/stdin-pipe-input-fallback
Closed

fix(cli): PipeInput fallback when kqueue rejects stdin fd#9996
sougannkyou wants to merge 1 commit into
NousResearch:mainfrom
sougannkyou:fix/stdin-pipe-input-fallback

Conversation

@sougannkyou
Copy link
Copy Markdown

Problem

On macOS with uv-managed cPython or inside IDE terminals (Kiro, VS Code), fstat(0) passes but the kqueue selector raises OSError [Errno 22] Invalid argument when prompt_toolkit tries to register fd 0 for async reads. The existing fstat() guard misses this case, causing an unhandled crash at startup:

File "selectors.py", line 523, in register
    self._selector.control([kev], 0, 0)
OSError: [Errno 22] Invalid argument

Related: #6393

Root Cause

The current pre-flight check only calls os.fstat(0) which verifies the file descriptor exists, but does not verify it can be registered with the kqueue/epoll selector that asyncio and prompt_toolkit rely on. In certain environments (uv-managed Python on macOS, IDE embedded terminals), fd 0 is valid but not watchable by kqueue.

Fix

  1. Selector probe — before creating the Application, test DefaultSelector().register(0, EVENT_READ). If it fails, activate the fallback path.
  2. PipeInput fallback — create a PipeInput via create_pipe_input() and pass it as input= to the Application, so prompt_toolkit never touches fd 0 directly.
  3. Stdin feeder thread — a daemon thread reads from real sys.stdin line-by-line and forwards into the pipe via send_text(), so keystrokes still reach the TUI.
  4. Safety net — add "Invalid argument" to the existing OSError catch block as defense-in-depth.
  5. Cleanup — close the PipeInput context manager in the finally block.

Testing

  • macOS 15 (Apple Silicon), uv-managed cPython 3.11.14
  • Normal terminal: selector probe passes → no fallback, behavior unchanged
  • IDE terminal (Kiro): selector probe fails → PipeInput fallback activates → CLI starts without crash

…follow-up)

On macOS with uv-managed cPython or inside IDE terminals (e.g. Kiro,
VS Code), fstat(0) passes but the kqueue selector raises
OSError [Errno 22] Invalid argument when prompt_toolkit tries to
register fd 0 for async reads. The existing fstat() guard misses
this case, causing an unhandled crash at startup.

Fix:
1. Probe the actual selector with register(0, EVENT_READ) before
   creating the Application. If it fails, create a PipeInput and
   pass it as input= to prompt_toolkit.
2. A stdin feeder daemon thread reads from real sys.stdin and
   forwards lines into the pipe, so keystrokes still reach the TUI.
3. Add 'Invalid argument' to the existing OSError catch as a
   last-resort safety net.
4. Clean up the PipeInput context manager in the finally block.
@teknium1
Copy link
Copy Markdown
Contributor

Closing — superseded by #26077 (merged as commit d3d5916), which preventively probes kqueue at startup and falls back to SelectSelector when fd 0 cannot be registered. The widened except-clause matching EINVAL / EBADF / 'Invalid argument' — which most PRs in this cluster including yours added — is also included.

Thanks for the fix; closing as duplicate of the merged work.

@teknium1 teknium1 closed this May 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants