Repository navigation
[Windows][WSL] Send button stays disabled after the first message (no turn/start is sent) #46775
Description
What happens
On Windows with WSL2 mode enabled ([desktop] runCodexInWindowsSubsystemForLinux = true), a thread only accepts the first message. After that turn finishes, the send button stays greyed out and clicking it does nothing.
- The first message sends and completes normally.
- Then the send button is disabled. Typing still works, but nothing can be submitted.
- The unsent text stays in the composer as a draft (persisted in
composer-prompt-drafts-v2in the app state). - Restarting the app does not help. Re-opening the thread (which triggers a successful
thread/resume) does not help either. - Workaround that does work: switch to another thread and back, or start a new thread.
Environment
- Codex desktop app (Windows, Microsoft Store): 26.915.31945
- app-server: 0.155.0-alpha.9.2
- Windows 11 + WSL2 (Ubuntu 24.04)
- Agent mode: full access
Key observation
After the first turn completes, no turn/start request is ever sent to the app-server — the message never leaves the UI. So this is a client-side disabled button, not a failed request.
The app log shows turn events being dropped by the renderer, because the conversation lookup uses a turn id where a thread id is expected:
error [electron-message-handler] Received turn/started for unknown conversation conversationId=01a0bdb0-cfc6-...
error [electron-message-handler] Received turn/started for unknown conversation conversationId=01a0bdb0-d152-...
error [electron-message-handler] Received turn/completed for unknown conversation conversationId=01a0bdb0-d152-...
Because those events are dropped, the per-thread "busy" flag is never cleared. The busy check in the WebView bundle (app.asar, decompiled) is:
if (unconfirmedTurnSubmissions?.some(e => e.terminal !== true)) return true;
if (resumeState === 'needs_resume') return threadRuntimeStatus?.type === 'active';
if (turns.length === 0) return resumeState === 'resuming';
return lastTurn(turns)?.status === 'inProgress';Any of these being true disables the composer. The resume response already reports the turn as completed, so the state is stuck on one of the other branches.
Timeline (UTC)
| Time | Event |
|---|---|
| 07:21:17 | 1st message: turn/start sent, turn runs |
| 07:23:32 | 1st turn completes (task_complete) |
| 07:24 – 07:42 | 18 minutes with zero turn/start requests, while the user was typing and clicking send |
| 07:33:17 | thread/resume succeeds (assignedStreamRole=owner), button still disabled |
| 07:40 | user switches to another thread and back |
| 07:42:50 | 2nd message finally sends (turn/start, took 2.3 s) |
Possibly related
WSL-mode latency is much worse than Windows-native here: turn/start takes ~2.3 s, one thread/resume took 17 s, and the app-server request queue overflowed with App server request expired while queued (-32001). A single turn also logs hundreds of [spawn-async] Spawning process inside WSL lines, which may be related to #46703 (concurrent wsl.exe probes crashing the Interop server).
Regression
Sessions from 2026-09-17 (app 26.911) contain many messages in one thread. Since 2026-09-19 (app 26.915), every thread gets exactly one message and then the send button is disabled.
Activity
github-actions commentedon Sep 20, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action