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
wmux disappears instantly — the entire window, every workspace, every pane, with no error dialog and nothing written to the sidebar. It reads like a process kill, not a UI fault. Roughly once every 2–4 days under normal use.
0xc0000409 here is not memory corruption — parameter 7 means the process deliberately called __fastfail(FAST_FAIL_FATAL_APP_EXIT), i.e. the CRT abort() path.
Evidence: 12 crashes, one signature
The Windows Event Log records 12 crashes between 2026-06-27 and 2026-08-04. I have minidumps from %LOCALAPPDATA%\CrashDumps for the 8 most recent, and every one is identical:
Crash time (local)
wmux version
Exception
Param
Fault offset
Crashing thread
2026-07-19 15:40:37
0.25.0
0xc0000409
0x7
wmux.exe+0x3290be5
index 0 (main)
2026-07-22 14:04:18
0.27.2
0xc0000409
0x7
wmux.exe+0x3290be5
index 0 (main)
2026-07-22 14:05:48
0.29.1
0xc0000409
0x7
wmux.exe+0x3290be5
index 0 (main)
2026-07-25 11:10:17
0.30.0
0xc0000409
0x7
wmux.exe+0x3290be5
index 0 (main)
2026-07-29 19:41:32
0.30.0
0xc0000409
0x7
wmux.exe+0x3290be5
index 0 (main)
2026-07-30 10:20:32
0.38.0
0xc0000409
0x7
wmux.exe+0x3290be5
index 0 (main)
2026-08-02 12:44:53
0.39.1
0xc0000409
0x7
wmux.exe+0x3290be5
index 0 (main)
2026-08-04 11:52:55
0.41.0
0xc0000409
0x7
wmux.exe+0x3290be5
index 0 (main)
The four older Event Log entries (0.10.0, 0.15.0, 0.17.0, 0.20.0) carry the same exception code and parameter; the two oldest sit at a different offset (+0x45e3515), which is consistent with the same bug before an Electron bump.
Note the two crashes 90 seconds apart on 07-22: restarting wmux hit the same path almost immediately.
Root cause: an unhandled C++ Napi::Error thrown inside conpty.node
The faulting stack carries both the raise path and the abort path, which means the exception was never handled:
The stack also contains 0xE06D7363 (MSVC C++ EH exception code, "msc") and 0x19930520 (C++ EH magic), so it is a C++ throw, not an SEH fault.
Decoding the EXCEPTION_RECORD gives a well-formed C++ throw record (NumberParameters=4, ExceptionInformation[0] == 0x19930520). Walking _ThrowInfo -> _CatchableTypeArray -> TypeDescriptor yields the thrown type:
And critically, ExceptionInformation[3] (the throw's image base) equals the load address of resources\app.asar.unpacked\node_modules\node-pty\prebuilds\win32-x64\conpty.node
in every dump — the _ThrowInfo lives in that module's .rdata, so the throw statement is compiled into conpty.node.
So: conpty.node throws Napi::Error in a context with no handler. The C++ exception escapes into the main thread's message loop, the CRT unhandled-exception path calls abort(), and the Electron browser process dies — taking every pane with it.
Because a Napi::Error thrown at a normal N-API method boundary is caught by node-addon-api's wrapper and converted into a JS throw, the fact that it reached UnhandledExceptionFilter means the throw happened outside such a boundary.
A Napi::Error thrown from a TSFN/libuv callback runs on the main thread with no node-addon-api try/catch above it — which matches all observed facts (main thread, shallow ~24 KB stack, no handler). That would make the trigger a pane's shell process exiting, which fits the irregular every-few-days cadence.
To be explicit: this last section is inference from the module's string table and the crashing thread's identity, not something I proved from the dump. Everything in the previous section is proven.
For completeness, the JS call sites into the native module are unguarded (windowsPtyAgent.js:123/130/150/156), but wrapping them in try/catch would not fix this — the exception never becomes a JS exception.
Suggested next steps
You can symbolize this quickly: the crash is at wmux.exe+0x3290be5 in the 0.41.0 build (time stamp 0x6a3b18dc), and conpty.node ships with a PDB path of D:\a\_work\1\s\build\Release\conpty.pdb. I'm happy to upload the minidumps (~6 MB each) if that would help — just say where.
A cheap hardening regardless of the exact throw site: build/ship conpty.node with NAPI_DISABLE_CPP_EXCEPTIONS, so N-API failures surface as JS errors instead of C++ throws that can abort the process.
The current dumps are minidumps, so the Napi::Error message is unrecoverable: Napi::Error::_message is lazily computed and still empty at throw time, and the text lives in the V8 heap behind a napi_ref. Setting
Environment
2.1.27949 git hash: bbf3d8a47552node-pty: 1.1.0 (resources/app.asar.unpacked/node_modules/node-pty), ConPTY backendSymptom
wmux disappears instantly — the entire window, every workspace, every pane, with no error dialog and nothing written to the sidebar. It reads like a process kill, not a UI fault. Roughly once every 2–4 days under normal use.
Windows records it as
Application Error/BEX64:0xc0000409here is not memory corruption — parameter7means the process deliberately called__fastfail(FAST_FAIL_FATAL_APP_EXIT), i.e. the CRTabort()path.Evidence: 12 crashes, one signature
The Windows Event Log records 12 crashes between 2026-06-27 and 2026-08-04. I have minidumps from
%LOCALAPPDATA%\CrashDumpsfor the 8 most recent, and every one is identical:The four older Event Log entries (0.10.0, 0.15.0, 0.17.0, 0.20.0) carry the same exception code and parameter; the two oldest sit at a different offset (
+0x45e3515), which is consistent with the same bug before an Electron bump.Note the two crashes 90 seconds apart on 07-22: restarting wmux hit the same path almost immediately.
Root cause: an unhandled C++
Napi::Errorthrown insideconpty.nodeThe faulting stack carries both the raise path and the abort path, which means the exception was never handled:
The stack also contains
0xE06D7363(MSVC C++ EH exception code, "msc") and0x19930520(C++ EH magic), so it is a C++throw, not an SEH fault.Decoding the
EXCEPTION_RECORDgives a well-formed C++ throw record (NumberParameters=4,ExceptionInformation[0] == 0x19930520). Walking_ThrowInfo -> _CatchableTypeArray -> TypeDescriptoryields the thrown type:And critically,
ExceptionInformation[3](the throw's image base) equals the load address ofresources\app.asar.unpacked\node_modules\node-pty\prebuilds\win32-x64\conpty.nodein every dump — the
_ThrowInfolives in that module's.rdata, so thethrowstatement is compiled intoconpty.node.So:
conpty.nodethrowsNapi::Errorin a context with no handler. The C++ exception escapes into the main thread's message loop, the CRT unhandled-exception path callsabort(), and the Electron browser process dies — taking every pane with it.Because a
Napi::Errorthrown at a normal N-API method boundary is caught by node-addon-api's wrapper and converted into a JSthrow, the fact that it reachedUnhandledExceptionFiltermeans the throw happened outside such a boundary.Where it likely comes from (inferred, not proven)
conpty.nodecontains these strings:node-pty's ConPTY path registers a process-exit callback via a ThreadSafeFunction (
windowsPtyAgent.js:89):A
Napi::Errorthrown from a TSFN/libuv callback runs on the main thread with no node-addon-api try/catch above it — which matches all observed facts (main thread, shallow ~24 KB stack, no handler). That would make the trigger a pane's shell process exiting, which fits the irregular every-few-days cadence.To be explicit: this last section is inference from the module's string table and the crashing thread's identity, not something I proved from the dump. Everything in the previous section is proven.
For completeness, the JS call sites into the native module are unguarded (
windowsPtyAgent.js:123/130/150/156), but wrapping them intry/catchwould not fix this — the exception never becomes a JS exception.Suggested next steps
wmux.exe+0x3290be5in the 0.41.0 build (time stamp 0x6a3b18dc), andconpty.nodeships with a PDB path ofD:\a\_work\1\s\build\Release\conpty.pdb. I'm happy to upload the minidumps (~6 MB each) if that would help — just say where.conpty.nodewithNAPI_DISABLE_CPP_EXCEPTIONS, so N-API failures surface as JS errors instead of C++ throws that can abort the process.remove_pty_batonMSVC assertion on close). This one is a different mechanism — a0xE06D7363C++ throw, not an assertion — and still reproduced on 0.41.0.How to capture better data
The current dumps are minidumps, so the
Napi::Errormessage is unrecoverable:Napi::Error::_messageis lazily computed and still empty at throw time, and the text lives in the V8 heap behind anapi_ref. Settingon an affected machine will capture the actual error message on the next occurrence.