ARM64 Windows: desktop app crashes ~16s after every launch - Codex Micro serialport addon delay-load failure (0xC06D007F)
ARM64 Windows: ChatGPT desktop crashes ~16s after every launch — Codex Micro serialport addon delay-load failure (0xC06D007F)
Summary
On ARM64 Windows, the ChatGPT desktop app's main (browser) process dies ~16 seconds after every launch. The window appears, then vanishes. It is 100% reproducible.
The cause is the bundled Work Louder / Codex Micro serialport native addon. It delay-imports napi_create_function from node.exe, which node-gyp's delay-load hook resolves to the host executable (ChatGPT.exe). ChatGPT.exe exports no N-API symbols — they live in chrome.dll. The lookup fails, the Visual C++ delay-loader raises 0xC06D007F, and because it's an SEH exception at dlopen time, the app's JS try/catch cannot catch it. The process dies.
Impact
Any ARM64 Windows user with Codex Micro enabled cannot open the app at all. First crash on this machine: 2026-07-15 ~11:52 ET, with no local change — consistent with a server-side rollout of the Codex Micro feature. The app was working normally before that.
Environment
| | |
|---|---|
| App | ChatGPT desktop (OpenAI.Codex) 26.707.9981.0, arm64, MSIX |
| ChatGPT.exe | 150.0.7871.115, built 2026-07-07 |
| Client version (logs) | 26.707.72221 |
| OS | Windows 11 build 26220, ARM64 (Surface Pro X / Snapdragon, 8 cores) |
| Serial devices | 6 COM ports present (4x Surface UART, 2x Bluetooth SPP) |
Root cause
Decoded DelayLoadInfo from the Crashpad minidump:
exception code : 0xC06D007F = VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND)
szDll : "node.exe"
szProcName : "napi_create_function"
fImportByName : 1
hmodCur : 0x7FF658A80000 -> ...\OpenAI.Codex_26.707.9981.0_arm64__2p2nqsd0c76g0\app\ChatGPT.exe
pfnCur : 0x0
dwLastError : 127 (ERROR_PROC_NOT_FOUND)
ptype : browser (main process -> whole app dies)
The szDll / szProcName strings live in the .rdata of:
app\resources\app.asar.unpacked\node_modules\@worklouder\device-kit-oai\
node_modules\@worklouder\wl-device-kit\node_modules\serialport\
node_modules\@serialport\bindings-cpp\prebuilds\win32-arm64\node.napi.node
Export tables confirm the mismatch:
| Binary | Total exports | N-API exports | napi_create_function? |
|---|---|---|---|
| ChatGPT.exe | 2 | 0 | NO |
| chrome.dll | 3174 | 158 | YES |
| chrome_elf.dll | 27 | 0 | NO |
node-gyp's stock win_delay_load_hook.cc intercepts the node.exe load and returns GetModuleHandle(NULL) — the host exe. In standard Electron that exe exports the N-API symbols. In this Chromium-shell architecture they're in chrome.dll, so the hook resolves to a module that cannot satisfy the import.
The first-party addons are built correctly and load fine — better_sqlite3.node, windows-account.node, windows-updater.node are all loaded in the same process at crash time. Only the vendored third-party prebuild is wrong. win32-arm64 is the only prebuild shipped, so there is no fallback.
Trigger path
renderer -> IPC -> CodexMicroHostService.getState()
-> eS.getService()
-> require('./codex-micro-service-CR6sUcZG.js')
-> top-level: createRequire(__filename)('@worklouder/device-kit-oai')
-> @worklouder/wl-device-kit -> serialport -> @serialport/bindings-cpp
-> LoadLibrary(prebuilds/win32-arm64/node.napi.node)
-> delay-load napi_create_function from ChatGPT.exe -> NULL -> 0xC06D007F -> fatal
The try/catch around discovery.findWLDevices([DeviceType.Project2077]) cannot help — the crash happens earlier, during require, and is a native SEH exception.
Reproduction
- ARM64 Windows 11, ChatGPT desktop 26.707.9981.0, Codex Micro enabled.
- Launch the app.
- ~16s later the main process dies; a Crashpad dump lands in
%LOCALAPPDATA%\Packages\OpenAI.Codex_2p2nqsd0c76g0\LocalCache\Roaming\Codex\web\Codex\Crashpad\reports.
Observed 3/3 launches, identical signature each time (dumps at 15:21:44, 15:36:45, 16:00:05).
Suggested fix
- Rebuild/relink the
@serialport/bindings-cppwin32-arm64 prebuild against the host that actually exports the N-API symbols (chrome.dll), matching how the first-party addons are built — e.g. a custom delay-load hook returningGetModuleHandle("chrome.dll")instead ofGetModuleHandle(NULL). node-hid'sHID.nodesits in the same@workloudertree and is very likely to hit the identical failure once serialport is fixed — please check it too.- Defensive: wrap the
codex-micro-servicerequire so a failure degrades the feature instead of killing the main process. (Note: an SEH delay-load failure is not catchable from JS — the real fix must be #1.) - Short term: consider gating the Codex Micro rollout off for ARM64 Windows until the addon is rebuilt. This unblocks affected users immediately.
Note
There is no user-side workaround. The broken file is inside the signed MSIX package, and Windows blocks modification even for an elevated Administrator that has taken ownership.
4 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Correction from the reporter: this is not ARM64-specific, and the root cause is the link method — please don't triage it as an arch/packaging fault
I filed this as an ARM64 problem. Further investigation shows that framing is wrong, and acting on it would produce a fix that doesn't fix anything. Corrections below, with the evidence.
1. x64 has the identical defect — binary-verified
I pulled the real x64 package from Microsoft's FE3/DeliveryOptimization CDN (
OpenAI.Codex_26.707.9981.0_x64__2p2nqsd0c76g0, 728,668,849 bytes,AppxManifestProcessorArchitecture="x64", same build number) and parsed it:| Binary (x64 package) | Exports | N-API exports |
napi_create_function? ||---|---|---|---|
|
ChatGPT.exe| 2 (GetHandleVerifier,IsSandboxedProcess) | 0 | NO ||
chrome.dll| 3174 | 145 | YES |And the x64 serialport binary delay-imports 53 napi symbols from
node.exe, includingnapi_create_function— the exact fatal linkage. The trigger JS is byte-identical (same Vite content hashcodex-micro-service-CR6sUcZG.js).The 2-export stub launcher is a property of the Chromium exe/
chrome.dllsplit. It is not arch-conditional. Any x64 user in the gate's rollout crashes identically.2. The real discriminator: normal-import vs delay-import
Parsing the import tables of every native addon in
app.asar.unpacked(note: the serialport path is 286 chars —os.walkand PowerShell-Recursesilently miss it; use\\?\):| Addon | Linkage | Result |
|---|---|---|
|
better_sqlite3.node| NORMAL import fromchrome.dll(74 fns) | works ||
pty.node| NORMAL import fromchrome.dll(38 napi incl.napi_create_function) | works ||
@worklouder/.../@serialport/bindings-cpp/prebuilds/win32-arm64/node.napi.node| DELAY import fromnode.exe(52 napi) | fatal ||
@worklouder/.../node-hid/build/Release/HID.node| DELAY import fromnode.exe| fatal |Your first-party addons were electron-rebuilt and link
chrome.dlldirectly. The vendored@worklouder/device-kit-oaisubtree was never electron-rebuilt — it ships stock npm artifacts that use node-gyp'swin_delay_load_hook, which resolvesnode.exe→GetModuleHandle(NULL)→ChatGPT.exe→ 0 napi exports →ERROR_PROC_NOT_FOUND(127) →0xC06D007F.node-hid'sHID.nodecarries the same defect and will fail the same way once serialport is fixed. Both need rebuilding.3. Not a "9981.0 crashes on launch" bug — it's gate-triggered
The renderer gates the whole path on a Statsig gate. In
app-main-DkkOUoXp.js:CodexMicroBridgeis the only boot-path caller ofcodexMicro.getState(), which reaches:Gate false → chunk never imported → no crash. Gate true → deterministic death ~16s after launch. Statsig fails closed, and the gate value is not persisted anywhere on disk, which is exactly why this is reboot-immune, reinstall-immune, and unfixable by the user.
Note the
try/catcharounddiscovery.findWLDevices([DeviceType.Project2077])cannot help — the fault is an SEH raised duringdlopen, before any JS frame exists to catch it.4. Suggested fix, in order
3207467860off for the affected cohort. That unblocks every affected user right now, on both architectures, with no client change.@worklouder/device-kit-oaisubtree (both@serialport/bindings-cppandnode-hid) so they normal-importchrome.dlllikebetter_sqlite3/ptyalready do — or give them a delay-load hook returningGetModuleHandle("chrome.dll")instead ofGetModuleHandle(NULL).prebuilds/win32-arm64with no fallback, so there is nothing for node-gyp-build to fall back to. Consider failing the require gracefully rather than letting an unrebuilt addon take down the browser process.5. Environment note
There is no user-side workaround. The addon lives inside the signed MSIX; Windows refuses modification even for an elevated Administrator who has taken ownership and granted themselves FullControl (no DENY ACEs, Controlled Folder Access off). Uninstall/reinstall returns the identical build. The Store serves no other version — FE3 exposes exactly one revision, and the separate "ChatGPT (Beta)" listing (
OpenAI.CodexBeta 26.707.3351.0) ships the identical defect.Affected users are simply stuck until the gate flips or a rebuilt package ships.
Closing as a duplicate of #33381 (ARM64 crash-loop) — the consolidated thread has the full analysis and @aonbrowser's working preload mitigation, which I've confirmed on my hardware.
Leaving one finding here that neither thread has, since it changes the scope of the fix.
#33375 and #33381 are the same defect on different architectures — and they ship different broken artifacts
#33375 (x64, "severe UI lag" + recurring Application Error 1000) and #33381 (ARM64, hard crash-loop) are the same bug. The differing symptom is just when the fatal delay-load lands: at boot on ARM64, on a retry path on x64.
I pulled the real x64 package from Microsoft's FE3/DeliveryOptimization CDN (
OpenAI.Codex_26.707.9981.0_x64__2p2nqsd0c76g0, 728,668,849 bytes,AppxManifestProcessorArchitecture="x64") and parsed it alongside the installed arm64 build:| Binary | arm64 | x64 |
|---|---|---|
|
ChatGPT.exeexports | 2 (GetHandleVerifier,IsSandboxedProcess), 0 napi | 2 (identical), 0 napi ||
chrome.dllnapi exports | 158 | 145 —napi_create_functionpresent || serialport addon | delay-imports
node.exe, 52 napi | delay-importsnode.exe, 53 napi |The 2-export stub launcher is a property of the Chromium
exe/chrome.dllsplit and is not arch-conditional. Sowin_delay_load_hook→GetModuleHandle(NULL)→ChatGPT.exe→ERROR_PROC_NOT_FOUNDfails identically on both.The scope-changing part — the two arches ship different artifacts:
Different files, same defect. Rebuilding only the arm64 prebuild will leave x64 broken, and vice versa.
node-hid'sHID.nodein the same@workloudersubtree carries the identical delay-import and needs the same treatment.The discriminator is link method, not architecture — verified across every native addon in the package:
| Addon | Linkage | Result |
|---|---|---|
|
better_sqlite3.node| NORMAL import ←chrome.dll| works ||
pty.node| NORMAL import ←chrome.dll| works ||
@worklouder/…/serialport| DELAY import ←node.exe| fatal ||
@worklouder/…/node-hidHID.node| DELAY import ←node.exe| fatal |First-party addons were electron-rebuilt. The vendored
@worklouder/device-kit-oaisubtree was not.Also ruled out, with evidence
26.707.9981.0, rev 1, x64 + arm64). There is no archive. The separate "ChatGPT (Beta)" listing (OpenAI.CodexBeta 26.707.3351.0, PE timestamp 19h before the stable build) ships the identical@worklouderdefect — not a downgrade.Gate
3207467860rollback remains the correct immediate vendor mitigation — it fixes both architectures at once with no client change.Duplicate of #33381.