Windows: startup bundled-plugins reconcile races Chrome extension-host.exe (EBUSY) — Computer Use + Chrome plugins disappear; CU helper "paths unavailable"
What version of the Codex App are you using (From “About Codex” dialog)?
26.602.9276.0 (also reproduced on 26.602.4764.0)
What subscription do you have?
Pro
What platform is your computer?
_No response_
What issue are you seeing?
On Windows, the desktop app's startup "bundled plugins reconcile" rebuilds %USERPROFILE%\.codex\.tmp\bundled-marketplaces\openai-bundled by deleting and re-copying it from the app bundle. If the Chrome plugin's native messaging host (extension-host.exe, spawned by Chrome, survives Codex restarts) is still running, it holds a handle inside that folder and the delete fails with EBUSY. The reconcile then aborts mid-way, leaving the runtime marketplace partially deleted (only plugins\chrome remains; .agents\plugins\marketplace.json is gone).
Consequences after every restart while Chrome's host is alive:
- Computer Use and Chrome plugins disappear from the marketplace/plugin model.
- The Computer Use native pipe fails on a loop (~every 10–30 s):
warning [computer-use-native-pipe] computer-use native pipe startup failed
errorMessage="Windows Computer Use helper paths are unavailable"
info [computer-use-native-pipe] computer-use notify config ensure finished
platform=win32 reason=missing-helper-path status=skipped
- Because the aborted reconcile is also what stages plugin caches, the per-user cache (
.codex\plugins\cache\openai-bundled\computer-use\<version>) is never populated for a new bundled plugin version after an app update. The CU helper resolver builds its path from the bundled manifest version (plugin.json→localVersion), so it points at a non-existent directory and throwsWindows Computer Use helper paths are unavailableeven thoughcodex-computer-use.exeships in the app bundle.
Key log lines from one startup (build 26.602.9276.0):
15:02:17.657Z info [bundled-plugins] bundled_plugins_reconcile_started reason=startup
15:02:32.863Z warning [BundledPluginsMarketplace] bundled_plugins_marketplace_resolve_failed
errorCode=EBUSY errorMessage="EBUSY: resource busy or locked, rmdir
'C:\Users\<user>\.codex\.tmp\bundled-marketplaces\openai-bundled\plugins\chrome\extension-host\windows\x64'"
15:02:33.976Z warning [computer-use-native-pipe] computer-use native pipe startup failed
errorMessage="Windows Computer Use helper paths are unavailable"
15:02:34.017Z info [bundled-plugins] bundled_plugins_reconcile_completed reason=startup
The lock holder (confirmed with a rename test + process inspection): a stale extension-host.exe running since a previous session, command line extension-host.exe chrome-extension://hehggadaopoacecdllhhajmbjkdcmajg/ --parent-window=0, image path .codex\plugins\cache\openai-bundled\chrome\latest\extension-host\windows\x64\extension-host.exe. It is launched by Chrome (native messaging), so quitting/restarting Codex does not stop it — one stale host breaks every subsequent launch.
What steps can reproduce the bug?
- Windows 11, Codex desktop app, Chrome plugin enabled, Codex Chrome extension installed and used at least once (so
extension-host.exeis running). - Quit Codex completely and relaunch it (the extension-host survives because Chrome owns it).
- Watch the desktop log:
bundled_plugins_marketplace_resolve_failed errorCode=EBUSY, then Computer Use + Chrome disappear from Plugins, and the computer-use native pipe loops"Windows Computer Use helper paths are unavailable".
What is the expected behavior?
Startup reconcile should tolerate a running extension-host: plugins should not vanish after a restart, and the Computer Use helper should start.
Additional information
Verified workaround (root-cause confirmation)
Kill the Chrome-extension host right before/while launching Codex so the reconcile window completes cleanly:
Get-CimInstance Win32_Process -Filter "Name='extension-host.exe'" |
Where-Object { $_.CommandLine -like '*hehggadaopoacecdllhhajmbjkdcmajg*' } |
ForEach-Object { Stop-Process -Id $_.ProcessId -Force }
# then launch Codex; reconcile completes with no EBUSY,
# computer-use native pipe reports "startup ready",
# and the reconcile itself re-stages the missing plugin cache version.
With this, the same build goes from permanently broken to fully working (verified across 5+ restarts), which confirms the race is the root cause. The host respawns afterwards and Chrome control keeps working.
Suggested fixes
- Stage the new marketplace copy to a temp directory and atomically swap/rename, instead of delete-then-recopy in place.
- Or: treat
EBUSYon individual entries as non-fatal (skip + retry) rather than aborting the whole reconcile, so other plugins (computer-use, marketplace.json) still get materialized. - Or: have the app terminate/coordinate with its own
extension-host.exebefore the reconcile delete. - Decouple cache staging from the
.tmprebuild so a failed.tmpdelete can't leave the Computer Use helper cache unstaged after an app update.
Environment
- Codex desktop (MSIX): 26.602.9276.0 (also reproduced on 26.602.4764.0)
- Bundled plugins version: 26.602.71036
- Windows 11 Enterprise 10.0.26200, x64
- Chrome with Codex extension (
hehggadaopoacecdllhhajmbjkdcmajg)
Possibly related: #25962, #26204 (same user-visible symptom "Computer Use unavailable" on Windows; the mechanism above may explain them).
5 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Additional confirmation from another Windows Codex Desktop install. This still reproduces on:
OpenAI.Codex_26.609.9530.0_x64__2p2nqsd0c76g0Observed on startup:
After that reconcile failure, the generated marketplace was left partially populated:
The generated copies of
browser,computer-use,latex, andsiteswere missing, including required files such as:browser/.codex-plugin/plugin.jsonbrowser/scripts/browser-client.mjscomputer-use/.codex-plugin/plugin.jsoncomputer-use/scripts/computer-use-client.mjsThe installed package source was intact and contained all bundled plugins:
The lock holder was a running Chrome native host process from the user plugin cache:
A non-destructive local repair confirmed the diagnosis: copying the missing plugin folders from the installed package back into the generated marketplace, while leaving the locked
chrome/extension-hostdirectory alone, restored the surfaces. After that:sky.list_apps()returned 40 appsiabextensionExpected behavior: bundled plugin reconcile should tolerate a running Chrome native host, or isolate that failure so one locked Chrome directory cannot leave the generated marketplace missing Browser/Computer Use/LaTeX/Sites. Reconcile should either skip the locked extension-host subtree, stage atomically, or stop/restart the native host before replacing it.
I traced the public repo side of this failure and prepared a tested mitigation branch, but I cannot open an upstream PR from this account because GitHub rejects
CreatePullRequestagainstopenai/codexfor this user. Leaving the patch here so a maintainer or someone with PR permission can cherry-pick it or open the upstream PR.Patch:
Public code paths I found:
codex-rs/core-plugins/src/store.rs: plugin cache install/replace/remove path.codex-rs/core-plugins/src/store_tests.rs: plugin cache unit tests.codex-rs/core-plugins/src/marketplace_upgrade/activation.rs: installed marketplace activation rollback logic.codex-rs/core-plugins/src/marketplace_upgrade/activation_tests.rs: added rollback coverage.Important limitation: the public checkout does not contain the Desktop bundled reconciler symbols from the logs (
BundledPluginsMarketplace,bundled_plugins_marketplace_resolve_failed,plugin_marketplace_folder_write_failed,extension-hostlaunch/native-host path generation, etc.). Those appear to live in Desktop/bundled private code. So this patch hardens the public plugin-cache side and adds regression coverage, but the Desktop bundled marketplace staging/reconcile code still needs a private-side fix.What the patch does:
remove_dir_all,remove_file, andrenameoperations when Windows reports lock-like failures (ACCESS_DENIED, sharing violation, lock violation, directory-not-empty)..tmp/bundled-marketplacesplugin source materializes into the stableplugins/cache/<marketplace>/<plugin>/<version>root rather than an active.tmppath.What still needs to happen in Desktop/private code:
marketplace.jsonand requiredplugin.jsonfiles, then atomically switch only after validation succeeds.extension-host.exeor a loaded native module still holds a handle, the old usable runtime marketplace should remain active.latest/active root that points into.tmp/bundled-marketplaces.Validation run on Windows:
just fix -p codex-core-pluginsclippy::large_enum_variantwarning incore-plugins/src/manifest.rs.just test -p codex-core-plugins.tmpcache-root regression.git diff --checkBundled plugin reconcile should be atomic and receipt-driven. Stage to a new directory, verify manifest and helper paths, swap by rename, and keep the previous good marketplace if cleanup hits EBUSY. A reconcile receipt with plugin, source version, lock holder if known, status, and rollback path would keep one Chrome host handle from removing unrelated tools.
---
_Generated with ax._
I maintain WinBridge Recovery, an independent Windows recovery tool for Codex Desktop: https://github.com/zemeng5208/winbridge-recovery
This is a strong match for the local-state recovery path the project handles. v3.1.1 already closes Chrome/Edge before repair, stops known Codex/browser helper processes, refuses to enter destructive replacement if targets are still locked, stages replacement content separately, validates it, and uses atomic swaps + rollback/backups for the marketplace/cache state. It also validates plugin versions,
latest, runtime paths, and Native Host state after recovery.The important part of this report is that killing a process name once is not enough when Chrome can immediately respawn the Native Messaging host. I am tracking more precise lock-owner diagnostics (PID / executable path / command line and path-based ownership) so the recovery flow can distinguish the Codex Chrome host from unrelated
node.exe/browser processes instead of using broad process-name kills.So if the failure is
EBUSY/os error 5leavingopenai-bundledpartial or the plugin cache/latestinconsistent, WinBridge is intended to help recover that state from the official installed package. It does not attempt to fix model-side Chrome routing or other upstream runtime behavior, and it will stop rather than force a swap while a target remains locked.