Windows Desktop: switching Agent environment to WSL2 fails startup with state db backfill handshake timeout

Open 💬 4 comments Opened Jul 31, 2026 by xiaodream551-a11y
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using (From “About Codex” dialog)?

  • MSIX package: OpenAI.Codex_26.727.4816.0_x64
  • Desktop build observed in logs / MCP env: 26.727.40816 / package 26.727.4816.0
  • WSL-side CLI available: codex-cli 0.146.0

What subscription do you have?

ChatGPT Pro (desktop signed in)

What platform is your computer?

  • Windows 11 25H2, build 26200, x64
  • WSL2 distro: Ubuntu-24.04 (default, Running)
  • WSL kernel: 6.18.33.2-microsoft-standard-WSL2
  • Windows user: Lenovo
  • WSL user: xdreamer (/home/xdreamer)

What issue are you seeing?

After changing Settings → Agent environment from Windows native to WSL2 / Windows Subsystem for Linux, Codex Desktop fails to start and shows:

ChatGPT failed to start.
Codex app-server initialize handshake timed out

Desktop logs show the app-server is launched inside WSL, then blocks on a state DB backfill from the Windows Codex home mounted at /mnt/c/..., and the Desktop 30s initialize handshake times out.

Sanitized Desktop log excerpt:

[wsl] eligible distro list listResult="NAME            STATE           VERSION\n* Ubuntu-24.04    Running         2"
[spawn-async] Spawning process inside WSL
[StdioConnection] stdio_transport_spawned
  executablePath=C:\Users\<user>\.codex\bin\wsl\<hash>\codex
  spawnCommand=wsl.exe
[AppServerConnection] Transport start success transport=stdio
[AppServerConnection] Initialize handshake still pending
  connectionError={"code":"connection-failed","message":"state db backfill is running at /mnt/c/Users/<user>/.codex; waiting up to 30s before retrying startup initialization"}
  durationMs=30011
initialize_handshake_result outcome=failure
  errorMessage="Codex app-server initialize handshake timed out"
app_server_connection.closed code=1
  reason="Error: failed to initialize sqlite state runtime under /home/<wsl-user>/.codex/sqlite: timed out waiting for state db backfill at /mnt/c/Users/<user>/.codex after 30s (status: running)"
Desktop bootstrap failed to start the main app phase=bootstrap-import-main

Important recovery detail:

  • %USERPROFILE%\.codex\.codex-global-state.json had "runCodexInWindowsSubsystemForLinux": false
  • but %USERPROFILE%\.codex\config.toml still had:
[desktop]
runCodexInWindowsSubsystemForLinux = true

Desktop continued spawning WSL until config.toml was set to false. After that:

stdio_transport_spawned executablePath=...\WindowsApps\OpenAI.Codex_...\app\resources\codex.exe
initialize_handshake_result durationMs=225 outcome=success

So WSL mode left the app unlaunchable, and the dual config sources made recovery non-obvious.

What steps can reproduce the bug?

  1. Use Codex Desktop on Windows with an existing local profile under %USERPROFILE%\.codex.
  2. Ensure WSL2 is installed with a default Ubuntu distro that is eligible (wsl -l -v shows Running / Stopped version 2).
  3. Open Codex Desktop in Windows native mode (works).
  4. Go to Settings and switch Agent environment to WSL / Windows Subsystem for Linux.
  5. Quit and relaunch Codex Desktop.
  6. Observe the fatal dialog:

Codex app-server initialize handshake timed out

  1. Inspect Desktop logs and observe WSL spawn + 30s state db backfill timeout from /mnt/c/Users/<user>/.codex into /home/<wsl-user>/.codex/sqlite.
  2. Set [desktop] runCodexInWindowsSubsystemForLinux = false in %USERPROFILE%\.codex\config.toml and relaunch.
  3. Observe Windows-native codex.exe spawn and a successful handshake in a few hundred ms.

Local size context (not multi-GB session history)

At failure time, approximate sizes under %USERPROFILE%\.codex:

logs_2.sqlite       ~438 MB
logs_2.sqlite-wal   ~14 MB
state_5.sqlite      ~1.7 MB
sessions            ~645 MB (127 files)
archived_sessions   ~103 MB (137 files)

This is much smaller than the multi-tens-of-GiB history case in #35674, but still enough for WSL-mode startup backfill over /mnt/c to exceed the fixed 30s Desktop handshake budget.

There was also a non-fatal warning while launching WSL mode:

bundled_executable_relocation_failed
executableName=bwrap
sourcePath=...\app\resources\codex-resources\bwrap
ENOENT

That appears secondary; the fatal path is the state db backfill timeout.

What is the expected behavior?

  1. Switching Agent environment to WSL2 should either:
  • complete first-run / state backfill successfully, or
  • open the app with a progress/recovery UI instead of a fatal handshake timeout.
  1. State DB backfill / SQLite init performed over /mnt/c should not be on a hard 30s critical path that prevents Desktop bootstrap.
  2. If WSL mode fails, Desktop should provide a one-click fallback to Windows native mode without requiring manual edits of config files.
  3. runCodexInWindowsSubsystemForLinux should have a single source of truth. Having .codex-global-state.json say false while config.toml [desktop] still says true (and Desktop obeys the latter) makes recovery confusing when the app cannot open Settings.
  4. Diagnostic logs / DB maintenance should not block app launch; if backfill is required, it should be resumable and backgrounded.

Additional information

Related issues (same failure family, different emphasis):

  • #35674 — large long-lived session history blocks startup during state DB backfill
  • #27741 — large logs_2.sqlite causes startup SQLite/pool timeout (often under WSL /mnt/c)
  • #32902 — WSL switch fails during provisioning / history display issues
  • #28087 — stuck on sqlite state backfill
  • #17254 / older WSL agent mode startup failures

This report is specifically about:

  1. Agent environment → WSL2 as the trigger
  2. Desktop spawning WSL app-server
  3. fatal state db backfill ... after 30s during initialize handshake
  4. dual config sources (config.toml vs .codex-global-state.json) complicating recovery

Workaround that restored launch on this machine:

# %USERPROFILE%\.codex\config.toml
[desktop]
runCodexInWindowsSubsystemForLinux = false

I can provide additional sanitized Desktop log excerpts if useful. I am not attaching raw session JSONL / auth / full SQLite dumps because they contain local paths and conversation content.

View original on GitHub ↗

4 Comments

github-actions[bot] contributor · 27 days ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #35674

Powered by Codex Action

anghel4d · 24 days ago

Additional reproduction on NixOS WSL2, with a non-destructive recovery

I reproduced this on a current Desktop build with NixOS as the WSL2 distribution. This adds two useful findings:

  1. NixOS and the WSL launch itself were healthy; the synchronous state backfill exceeded Desktop's fixed 30-second initialize deadline.
  2. On this build, the backfill continued after Desktop reported bootstrap failure. Letting it finish and then relaunching repaired WSL mode without deleting or moving any user data.
Environment
  • Codex Desktop package: OpenAI.Codex_26.727.6591.0_x64
  • WSL-side app-server: 0.146.0-alpha.9.2
  • Windows 11 Pro x64, build 26200
  • WSL2 kernel: 6.18.33.2-microsoft-standard-WSL2
  • Distribution: NixOS 26.11.20260729.0954f7e
What happened

The Desktop successfully discovered NixOS and spawned the relocated Linux binary through wsl.exe:

[StdioConnection] stdio_transport_spawned ... spawnCommand=wsl.exe
[AppServerConnection] Transport start success ... transport=stdio

The actual WSL process was alive with valid stdin/stdout pipes, a valid working directory, the expected HOME, and the intended split state paths:

CODEX_HOME=/mnt/c/Users/<user>/.codex
CODEX_SQLITE_HOME=/home/<user>/.codex/sqlite

At exactly 30 seconds, Desktop failed the bootstrap:

Initialize handshake still pending ... durationMs=30011
initialize_handshake_result durationMs=30012
errorMessage="Codex app-server initialize handshake timed out"
outcome=failure
Desktop bootstrap failed to start the main app

However, the app-server process remained alive and continued building:

/home/<user>/.codex/sqlite/state_5.sqlite

The source Windows state_5.sqlite was approximately 125.2 MB. During the failed launch, the WSL-local database grew continuously to approximately 122.8 MB plus its WAL. At about 69 seconds after spawn, its backfill_state changed to:

status = complete

It contained:

  • 1,128 threads, matching the Windows state DB
  • 99 thread spawn edges, matching the Windows state DB
  • 44 applied SQLx migrations
  • PRAGMA quick_check(1) = ok

The transport stopped shortly after the backfill reached complete.

Non-destructive recovery observed

I then relaunched Desktop without changing configuration, deleting data, reinstalling, or shutting down WSL. The same WSL backend initialized successfully:

initialize_handshake_result durationMs=2826 outcome=success
Codex CLI initialized
app_server_connection.state_changed ... next=connected
window ready-to-show

For a profile of this size, the effective workaround was therefore:

  1. Start Desktop in WSL mode.
  2. After the 30-second failure, leave the process alone long enough for the first WSL state backfill to finish (roughly another 40 seconds in this case).
  3. Close/relaunch Desktop.
  4. Subsequent WSL initialization completes within the handshake budget.

This is much safer than deleting SQLite state or moving session history, although it may not work for very large profiles if Desktop terminates the backfill before it can complete.

NixOS and bwrap findings

The preliminary suspicion that this was a NixOS launch/shell problem was ruled out:

  • WSL startup was fast.
  • /usr/bin/bash worked.
  • The relocated Codex binary launched and handled app-server requests.
  • The successful second launch used the same command and environment.

Desktop also logged the known warning that its packaged codex-resources/bwrap was absent. NixOS supplied /run/current-system/sw/bin/bwrap, and the second launch succeeded despite the same relocation warning, so that warning was not causal here.

Suggested fix

The state migration/backfill should not share a fatal 30-second deadline with the app-server protocol handshake. Possible approaches:

  • complete or resume the migration before starting the handshake deadline;
  • expose a migration-progress/heartbeat state and keep Desktop open with progress UI;
  • allow the app-server to initialize while historical backfill proceeds asynchronously;
  • reconnect automatically when a still-running backfill reaches complete; or
  • at minimum, present a safe “wait and relaunch” recovery action instead of a generic fatal startup error.

The key evidence here is that the supposedly failed app-server was healthy and made measurable progress, and the exact same backend initialized in 2.826 seconds once its one-time WSL-local backfill had completed.

xlr1012514182 · 19 days ago

nice issue!

T-Higgins · 23 hours ago

Having this issue too.