You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On Windows, exiting opencode in its default server+TUI mode (via /exit or Ctrl+C×2) kills the parent shell when that shell is hosted in a ConPTY (the standard Win32 pseudoconsole used by every modern Windows terminal: Warp, Windows Terminal, VS Code, etc.). The same opencode binary, run from a native conhost.exe window, leaves the parent shell alive. This points at console-handle / FreeConsole cleanup in opencode (or its bun runtime) that is benign against full conhost but corrupts ConPTY's internal state.
The user-visible symptom is that the host terminal's pane closes immediately, because the host terminal correctly reacts to its child shell dying.
This is a more focused diagnosis of the same issue partially addressed in #6189 (closed). #6189 only covered the Ctrl+C key-handler exit path; the bug here reproduces equally on /exit and is not about input handling.
Differential reproduction matrix
Console host
opencode mode
Parent shell dies?
conhost.exe (classic Windows console window)
default (server+TUI)
No
ConPTY (Warp / Windows Terminal / VS Code)
default
(server+TUI)
**Y
ConPTY
opencode serve … + opencode attach …
No
ConPTY, with `cmYes**
ConPTY, with powershell -NoExit -Command "opencode"
default
Yes
Three things narrow the cause:
**Console-host ted shells die.Native conhost is fine.
Server-child dependent — opencode attach (no spawned server child) is fine. The trigger is in the cleanup path of the server child opencode forks in default mode.
Shell agnostic — both PowerShell and cmd die. So it isn't PowerShell's .NET Console doing something special; it's something happening to the shared ConPTY console state that any shell will then trip over.
Captured shell exit code (PowerShell case)
I instrumented Warp's Windows PTY callback to call GetExitCodeProcess on the shell handle the moment ChildExitWatcher fires:
ChildExitWatcher: shell process handle signaled, exit_code=0x80131623 (2148734499), sending Message::ChildExited to
event loop
Decoding 0x80131623:
bit 31 (severity) = 1 (error)
facility = 0x013 = FACILITY_URT (.NET CLR)
code = 0x1623, range = .NETSystem.IO / ObjectDisposedException family.
I.e., PowerShell truntime threw anunhandled exception when next accessing the Console** (e.g., Console.In/Console.Out reading from a stream backed by a now-disposed/closed handle). With cmd as the host shell the exact code is presumably different, but the precondition is the same: ConPTY console state has been left in a state that the next console read fails.
This pattern is co
The server child or its child processes calling FreeConsole (and/or AttachConsole) on shutdown. Microsoft's own ConPTY documentation explicitly notes that FreeConsole/AttachConsole are not fully suppave thepseudoconsole in an inconsistent state (which is invisible under classic conhost because conhost manages console attachment via kernel objects rather than pipe state).
Closing inheritendles in a waythat, in pipe-backed ConPTY, causes the underlying pipe to advance to EOF for everyone — even though the same close is a no-op for other consumers under conhost's reference-counted console-object model.
bun runtime fd cleanup ([bun-issues that touch console handles in the past] FYI for cross-reference) treating console handles like ordinary fds and close()-ing them.
What I'd like to learn from the opencode side
Verifying which ither fix itupstream or file a precise bug at bun/Go runtime. Concrete asks:
On Windows, doecode serveprocess when default mode forks it) callFreeConsole, AttachConsole, SetStdHandle, or CloseHandleon any ofSTD_INPUT_HANDLE/STD_OUTPUT_HANDLE/STD_ERROR_HANDLE` during shutdown?
Is the server child created with bInheritHandles = TRUE and the parent's std handles inherited as-is? If so, does the server child later close those handles, even via the runtime's automatic
fd-on-exit cleanup
Prior opencode iixed part of theCtrl+C path; /exit still reproduces.
Environment
OS: Windows 11 Home, build 26200
Shell tested: PowerShell 7 (also reproduces in cmd /k opencode and powershell -NoExit -Command "opencode")
Console hosts tested: ConPTY (via Warp) reproduces; classic conhost.exe does not
opencode version 如 1.0.202>`
Repro is 100% de
I'm happy to capture additional traces (Process Monitor, WinDbg post-mortem, etc.) if that helps narrow down the exact API call.
Plugins
No response
OpenCode version
No response
Steps to reproduce
On Windows 11, open a ConPTY-backed terminal — any of: Warp, Windows Terminal, VS Code's integrated terminal.
In the resulting PowerShell 7 (or pwsh) prompt, run:
opencode
Wait for the OpenCode TUI to load.
Exit OpenCode using either of:
Type /exit and press Enter, or
Press Ctrl+C twice in quick succession.
Observed: the parent PowerShell process terminates immediately (the host terminal pane closes, because the host correctly reacts to its child shell dying). On Warp the pane vanishes; on Windows Terminal the tab closes; on VS Code the integrated terminal session ends.
Expected: OpenCode exits and control returns to the PowerShell prompt, which is what happens in a native conhost.exe window with the same opencode binary.
Description
Summary
On Windows, exiting
opencodein its default server+TUI mode (via/exitor Ctrl+C×2) kills the parent shell when that shell is hosted in a ConPTY (the standard Win32 pseudoconsole used by every modern Windows terminal: Warp, Windows Terminal, VS Code, etc.). The same opencode binary, run from a nativeconhost.exewindow, leaves the parent shell alive. This points at console-handle /FreeConsolecleanup in opencode (or its bun runtime) that is benign against full conhost but corrupts ConPTY's internal state.The user-visible symptom is that the host terminal's pane closes immediately, because the host terminal correctly reacts to its child shell dying.
This is a more focused diagnosis of the same issue partially addressed in #6189 (closed). #6189 only covered the Ctrl+C key-handler exit path; the bug here reproduces equally on
/exitand is not about input handling.Differential reproduction matrix
conhost.exe(classic Windows console window)opencode serve …+opencode attach …powershell -NoExit -Command "opencode"Three things narrow the cause:
opencode attach(no spawned server child) is fine. The trigger is in the cleanup path of the server child opencode forks in default mode..NET Consoledoing something special; it's something happening to the shared ConPTY console state that any shell will then trip over.Captured shell exit code (PowerShell case)
I instrumented Warp's Windows PTY callback to call
GetExitCodeProcesson the shell handle the momentChildExitWatcherfires:ChildExitWatcher: shell process handle signaled, exit_code=0x80131623 (2148734499), sending Message::ChildExited to
event loop
Decoding
0x80131623:0x013=FACILITY_URT(.NET CLR)0x1623, range = .NETSystem.IO/ObjectDisposedExceptionfamily.I.e., PowerShell truntime threw anunhandled exception when next accessing the Console** (e.g.,
Console.In/Console.Outreading from a stream backed by a now-disposed/closed handle). With cmd as the host shell the exact code is presumably different, but the precondition is the same: ConPTY console state has been left in a state that the next console read fails.This pattern is co
FreeConsole(and/orAttachConsole) on shutdown. Microsoft's own ConPTY documentation explicitly notes thatFreeConsole/AttachConsoleare not fully suppave thepseudoconsole in an inconsistent state (which is invisible under classic conhost because conhost manages console attachment via kernel objects rather than pipe state).close()-ing them.What I'd like to learn from the opencode side
Verifying which ither fix itupstream or file a precise bug at bun/Go runtime. Concrete asks:
process when default mode forks it) callFreeConsole,AttachConsole,SetStdHandle, orCloseHandleon any ofSTD_INPUT_HANDLE/STD_OUTPUT_HANDLE/STD_ERROR_HANDLE` during shutdown?bInheritHandles = TRUEand the parent's std handles inherited as-is? If so, does the server child later close those handles, even via the runtime's automaticfd-on-exit cleanup
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)or(CTRL_BREAK_EVENT, 0)against the shared console? (Already partly addressed by In the Windows system, pressing Ctrl+C will automatically exit the terminal #6189, but worth confirming for the/exitpath too.)A minimal mitigation that has worked for similar issues in other projects:
(`CREATE_NEW_CONSOo it can nevershare console handles with the user's interactive shell.
Cross-references
/exitstill reproduces.Environment
cmd /k opencodeandpowershell -NoExit -Command "opencode")conhost.exedoes notI'm happy to capture additional traces (Process Monitor,
WinDbgpost-mortem, etc.) if that helps narrow down the exact API call.Plugins
No response
OpenCode version
No response
Steps to reproduce
pwsh) prompt, run:Screenshot and/or share link
No response
Operating System
Windows 11
Terminal
Warp