Skip to content

TUI wedges mid-turn (screen clears, input dead, Ctrl+C/Ctrl+\ ignored) — write EIO on stdout followed by EPIPE on Rust JSON-RPC transport; WSL2 + Windows Terminal #4069

Description

@msmbaldwin

Copilot CLI — mid-turn screen clear / unresponsive terminal

Environment

  • CLI version: 1.0.70-0
  • Node: v24.11.1
  • OS: WSL2 (Ubuntu) on Windows 11
  • Terminal: Windows Terminal
  • Model in use: claude-opus-4.7

Symptom

While the assistant is actively working in a session (streaming a reply and/or
running tools mid-turn), the CLI's terminal pane suddenly:

  1. Clears to a blank alternate-screen buffer (just a cursor at column 0)
  2. Stops rendering any further output
  3. Stops accepting input — typing does nothing
  4. Ignores Ctrl+C and Ctrl+\ (SIGQUIT)
  5. The underlying copilot node process remains alive; only tab-close /
    external kill -9 from another shell (or a reboot) recovers the terminal

Not idle-related. Reproduced within ~10 minutes of a fresh boot, mid-turn.
Multiple sessions in the same day exhibited it.

What is NOT happening

  • Not caused by leaving the CLI idle (initially suspected, ruled out — happens
    mid-turn during active streaming/tool use).
  • Not a terminal resize (no SIGWINCH in the timeline).
  • Not user-initiated shutdown (no Ctrl+D, no /exit, no window close).

Log signature

Recent process logs under ~/.copilot/logs/ for wedged sessions contain this
pattern around the point of failure:

[DEBUG] Ignoring transient stdout error: write EIO
[DEBUG] Uncaught Exception (transient I/O, suppressed): write EPIPE
Error: write EPIPE
[ERROR] Rust JSON-RPC transport error: Error: write EPIPE
...
[DEBUG] [shutdown] Starting dispose: InkInstance.rerender
[DEBUG] Ignoring transient stdout error: write EIO
[DEBUG] [shutdown] Completed dispose: InkInstance.rerender (65ms)

The write EIO on stdout and write EPIPE on the Rust JSON-RPC transport
cluster together, then Ink attempts a shutdown re-render. This looks like the
Ink renderer (or something writing to stdout in parallel with it) hits EIO,
which then cascades EPIPE across the extension-host IPC pipes. Because the
CLI classifies EIO as "transient" and does not abort, the process keeps
running with a dead TTY — no input handler, no visible output.

Contributing hypothesis: high re-render rate during streaming
(assistant.streaming_delta + assistant.tool_call_delta events) combined
with concurrent writers to stdout produces a short window where a write races
with something (terminal state change? SIGWINCH from Windows Terminal?
extension-host handshake?) and stdout returns EIO. Once stdout is EIO, Ink
can no longer paint and the input reader also stalls.

Wedged process observations

Example: PID 2160 (copilot, pts/2), state Sl+, still alive over an hour
after the wedge. Log
~/.copilot/logs/process-1783606860101-2160.log shows normal activity, then
only ExP telemetry heartbeats every ~10 minutes — no user input events, no
render updates. Consistent with "TUI/input loop dead, background workers
alive."

Impact

  • Loss of the active turn's visible output (state is still on disk under
    ~/.copilot/session-state/<id>/ and resumable, but the in-progress reply
    is gone).
  • Ctrl+C / Ctrl+\ ineffective — no graceful shutdown path from within the
    wedged terminal.
  • Requires killing the process from a separate shell, or a system reboot in
    the worst case.

Requested fixes / improvements

  1. When stdout returns EIO repeatedly (say, more than N times in M ms),
    treat it as fatal instead of transient. Either:
    • attempt to reopen /dev/tty and re-attach Ink, or
    • exit cleanly with a diagnostic message.
  2. Ensure Ctrl+C and Ctrl+\ remain honored even if the Ink render loop
    is stalled — the SIGINT/SIGQUIT handler should not depend on the TUI
    being alive.
  3. Optional: a COPILOT_NO_ALT_SCREEN=1 / --no-alt-screen escape hatch
    that renders inline instead of using the alternate screen buffer, so a
    wedge doesn't hide scrollback and leaves recovery affordances visible.
  4. Investigate whether the extension-host EPIPE bursts (link-checker,
    stale-content-finder, pr-review-feedback, crlf-guard, frontmatter-validator,
    ms-date-auto-updater are all forked at startup on this system) contribute
    by writing to shared stdio pipes during a render.

Attachments to include when filing

Smallest logs that show the failure signature (attach one):

  • ~/.copilot/logs/process-1783610127464-4484.log (~2.2 MB, 13 EIO hits)
  • ~/.copilot/logs/process-1783610562915-6077.log (~0.6 MB, 8 EIO hits)

Larger log with the "wedged process kept running" evidence:

  • ~/.copilot/logs/process-1783606860101-2160.log (~7.7 MB)

Screenshots of the wedged tab (blank pane, cursor only, tab title still
present) are also useful.

Filing

Open at: https://github.com/github/copilot-cli/issues

Suggested title:

TUI wedges mid-turn (screen clears, input dead, Ctrl+C/Ctrl+\ ignored) —
write EIO on stdout followed by EPIPE on Rust JSON-RPC transport; WSL2

  • Windows Terminal

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions