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
Official runtime: ChatGPT Desktop for Linux 26.908.40834 (build 318576267-1789148373000); also reproduced on 26.903.61454, 26.908.31748, 26.820.71523
Access: browser (web-shell) over LAN, single user, gateway bound to 127.0.0.1
Symptom
After a session has been running for a while (idle periods produce nothing), the gateway log starts
spewing and never recovers until the gateway is restarted:
Failed to register AppView RPC services errorMessage="no such export ID: 622"
at oee.ensureResolvingExport (.../.data/cache/codex-official-bundle/.vite/build/src-DJnwJvdz.js:709:36337)
Failed to register AppView RPC services errorMessage="no such entry on exports table: -1"
at e.evaluateImpl (...)
Failed to register AppView RPC services errorMessage="MessagePort message error."
[electron-message-handler] sa_server_request_failed attachAuth=true attachIntegrityState=true
error={"name":"Error","message":"no such export ID: 1", ...}
[electron-message-handler] Failed to broadcast thread state patches conversationId=01a04794-... error=no such export ID: 1
User-visible effect: the page can no longer perform backend API requests (usage / account / remote
control etc.), and thread state / activity stops syncing for the affected conversations. Reloading the page does NOT recover it (measured: +4 sa_server_request_failed after Page.reload);
only systemctl restart ryensx-opencodex.service clears it.
Counts (single box, ~6 days, one user)
signal
total
Failed to register AppView RPC services
5359
sa_server_request_failed (no such export ID: 1)
37924
Failed to broadcast thread state patches
91480 (concentrated on 9 conversations, max 532 in one)
Idle 3-minute window: 2 new log lines, 0 failures → this is not a retry loop, it is accumulated state.
Direct evidence of the trigger
Every burst begins immediately after the gateway drops an app-host response to a dead client:
[2026-09-14T04:14:52.396Z] [ws-hub] send_to_missing_client {"channel":"codex_desktop:message-for-view","type":"mcp-response","requestId":"08fa6265-..."}
[2026-09-14T04:14:52.396Z] [ws-hub] send_to_missing_client {"channel":"codex_desktop:message-for-view","type":"mcp-response","requestId":"84bef983-..."}
[2026-09-14T04:14:52.399Z] [ws-hub] send_to_missing_client {"channel":"codex_desktop:message-for-view","type":"mcp-response","requestId":"bef99bc5-..."}
Failed to register AppView RPC services errorMessage="no such entry on exports table: -1"
Failed to register AppView RPC services errorMessage="no such export ID: 622"
...
(node:3185805) MaxListenersExceededWarning: Possible EventEmitter memory leak detected.
65 destroyed listeners added to [WebContents]. MaxListeners is 64.
Note the MaxListenersExceededWarning on [WebContents] (65 destroyed listeners): one AppView appears
to be registered per browser connection on the shared hidden webContents and they are never released
(the hidden window is never destroyed), while no such export ID: 1 shows the page-side RPC peer is
calling into an export table that no longer exists.
What we tried to reproduce (all clean, so it is accumulation, not a single code path)
probe (Chrome for Testing via CDP)
result
fresh page load, 25 s idle
0
load → cut network 20 s (WS drops) → restore (page auto-reconnects, no reload)
0
page A open, then page B opens (second tab), then B closes, then reload A
Official main registers an AppView per codex_desktop:connect-app-host on the shared hidden webContents
and only cleans up on webContentsdestroyed, so registrations accumulate (65 > 64 listeners).
Would the gateway need to dispose the previous AppView explicitly when a page reconnects / a relay is replaced?
Current mitigation
A 3-minute watchdog restarts the gateway when the per-interval delta of these log lines exceeds a
threshold (AppView ≥ 30 or sa_server_request_failed ≥ 90). It works, but it is a sledgehammer:
every recovery costs a ~60-90 s gateway restart and a page refresh.
Questions
Is there an intended way for the gateway to tear down / rebind an AppView for a still-alive hidden
webContents (e.g. when closeAppHostRelays(ws, "replaced") runs)?
Should mcp-response frames be dropped (and the route purged) once a clientId has no live socket,
or should the request be failed back to the caller instead?
Environment
2.1.0(f6fd79c) + PR fix(compatibility): support delegated worktree shell environment pattern #52 (b5c61e2), Linux, headless Electron runner(
.data/runtime/official-electron-runner/linux-x64/opencodex-gateway, flags:--no-sandbox --disable-setuid-sandbox --disable-dev-shm-usage --headless --disable-gpu)26.908.40834(build318576267-1789148373000); also reproduced on26.903.61454,26.908.31748,26.820.71523Symptom
After a session has been running for a while (idle periods produce nothing), the gateway log starts
spewing and never recovers until the gateway is restarted:
User-visible effect: the page can no longer perform backend API requests (usage / account / remote
control etc.), and thread state / activity stops syncing for the affected conversations.
Reloading the page does NOT recover it (measured: +4
sa_server_request_failedafterPage.reload);only
systemctl restart ryensx-opencodex.serviceclears it.Counts (single box, ~6 days, one user)
Failed to register AppView RPC servicessa_server_request_failed(no such export ID: 1)Failed to broadcast thread state patchesIdle 3-minute window: 2 new log lines, 0 failures → this is not a retry loop, it is accumulated state.
Direct evidence of the trigger
Every burst begins immediately after the gateway drops an app-host response to a dead client:
Note the
MaxListenersExceededWarningon[WebContents](65destroyedlisteners): one AppView appearsto be registered per browser connection on the shared hidden webContents and they are never released
(the hidden window is never destroyed), while
no such export ID: 1shows the page-side RPC peer iscalling into an export table that no longer exists.
What we tried to reproduce (all clean, so it is accumulation, not a single code path)
sa_server_request_faileddriftSuspects
rememberRequestRoute(channel, invokeArgs, clientId)keeps routing to aclientIdthat no longer has alive socket →
send_to_missing_clientdropsmcp-responseframes → the page-side app-host RPC nevercompletes its export registration. Related history: issue Chat history disappears after browser WebSocket reconnect #27 / PR fix(gateway): restore app-host relay after websocket reconnect #28 (
restore app-host relay after websocket reconnect).codex_desktop:connect-app-hoston the shared hidden webContentsand only cleans up on
webContentsdestroyed, so registrations accumulate (65 > 64 listeners).Would the gateway need to dispose the previous AppView explicitly when a page reconnects / a relay is replaced?
Current mitigation
A 3-minute watchdog restarts the gateway when the per-interval delta of these log lines exceeds a
threshold (AppView ≥ 30 or
sa_server_request_failed≥ 90). It works, but it is a sledgehammer:every recovery costs a ~60-90 s gateway restart and a page refresh.
Questions
webContents (e.g. when
closeAppHostRelays(ws, "replaced")runs)?mcp-responseframes be dropped (and the route purged) once aclientIdhas no live socket,or should the request be failed back to the caller instead?