Fix Codex’s missing browser service on WSL and Windows
Chrome connected, but Codex could not load browser-service.mjs. How a Windows/WSL marketplace conflict blocked plugin installation and how it was repaired.
On this page · 9 sections
- 01The failure happened before Chrome
- 02Why was the task loading code from a cache?
- 03Was the import hook changing the path?
- 04The startup log exposed the installation failure
- 05The first path change was incomplete
- 06The repair commands
- 07The runtime needed one more refresh
- 08What this repair establishes
- 09Sources
The ChatGPT extension reported that Chrome was connected, but a Codex browser call failed before reaching it. The Windows runtime tried to import a browser service from a plugin-cache directory that did not exist.
The current service was present in the installed Codex app. It was also present in the directory prepared for bundled-plugin installation. The installation step between that directory and the active cache had failed.
The failure happened before Chrome
The browser call returned this error:
Error
Cannot find module
'<CODEX_HOME>\plugins\cache\openai-bundled\browser\26.901.41123\scripts\browser-service.mjs'
imported from <TEMP>\<worker-directory>\trusted-worker.jsWhere it fails
The trusted worker imports the browser service from a versioned plugin-cache path. That cache entry did not exist, so the call failed before it reached Chrome.
Cause
The shared configuration registered the openai-bundled marketplace with its WSL path. The Windows desktop's own registration was rejected, so plugin installation was blocked and the cache kept Browser 26.727.40816.
Fix, in this order
Remove and re-add only the
openai-bundledmarketplace source, so Codex stores its own Windows form of the path.codex plugin marketplace remove openai-bundled --jsoncodex plugin marketplace add $bundledSource --jsonInstall the Browser and Chrome plugins.
codex plugin add browser@openai-bundled --jsoncodex plugin add chrome@openai-bundled --jsonReset the task's JavaScript kernel and load the newly installed client.
Tried first
Change the registered source to a Windows path with forward slashes.
Browser and Chrome installed, but marketplace reconciliation was not fully repaired.
- Desktop app
The desktop app was version
26.901.5003.0.- Bundled Browser component
Its bundled Browser component identified itself as
expected26.901.41123.Those are different version identifiers for the app package and its component, not evidence of a mismatch by themselves.
- Installed plugin cache
The cache contained only Browser version
present26.727.40816.The mismatch was between the component selected by the runtime and the installed plugin cache.
A host-side file check confirmed that the requested cache entry was absent. This mattered because a sandbox access failure alone would not establish that a Windows host file was missing.
At this point, the extension's connection indicator could not answer the relevant question. Chrome might be connected to its native host while the Codex task still fails to load the service needed to use that connection.
Why was the task loading code from a cache?
The word “cache” initially made the path look accidental. Inspection of the installed desktop code showed that it was deliberate. The app constructs a service path with this shape:
<CODEX_HOME>/plugins/cache/<marketplace>/<plugin>/<version>/scripts/browser-service.mjs
There were three copies or destinations to distinguish:
The application bundle contained the shipped Browser plugin and its service file.
current filesThe prepared marketplace directory, under
current files.tmp/bundled-marketplaces/openai-bundled, contained the current files that the plugin installer could consume.installation stepfailed
The installed plugin cache, under
older versionplugins/cache/openai-bundled/browser, contained the older installed version.
The task's Windows JavaScript runtime received a NODE_REPL_TRUSTED_SERVICES environment setting. Its browser entry pointed at the versioned cache path. The trusted worker reads this mapping and imports the configured service when the browser client calls it.
That also explains why importing a client from the Chrome plugin did not avoid the failure. The client and the service are separate modules. Choosing the client import does not replace the service mapping supplied by the desktop app.
The same mapping appeared in the shared .codex/config.toml. This was an application configuration problem encountered by one task. There was no evidence of a special redirect created for that conversation. Other tasks could still differ because their processes might already have loaded a service.
Was the import hook changing the path?
Part one introduced a PreToolUse hook to normalize dynamic imports passed from WSL to Windows Node. That made it a reasonable suspect.
The complete hook source was short enough to inspect directly. It reads JSON from standard input, looks at tool_input.code, and rewrites literal dynamic imports beginning with /mnt/<drive>/.
For example:
await import("/mnt/c/work/plugin/browser-client.mjs")
becomes:
await import("file:///C:/work/plugin/browser-client.mjs")
The hook does not choose a plugin version, write configuration, change environment variables, or delete files. The failing browser call already used a Windows drive path, which its rewrite rule would leave unchanged.
The missing service was imported later, inside the trusted worker, using NODE_REPL_TRUSTED_SERVICES. That was outside the hook's input-rewrite operation.
This source inspection did not establish whether the Linux-shaped hook command executed successfully in this Windows task. It did establish that its rewrite logic did not construct the failing service path. Disabling it would leave that path and the missing cache entry in place.
The startup log exposed the installation failure
The shared configuration registered the bundled marketplace using its WSL path:
[marketplaces.openai-bundled]
source_type = "local"
source = "/mnt/c/Users/<user>/.codex/.tmp/bundled-marketplaces/openai-bundled"
The Windows desktop tried to register the corresponding Windows directory:
C:\Users\<user>\.codex\.tmp\bundled-marketplaces\openai-bundled
The log recorded the rejection:
marketplace 'openai-bundled' is already added from a different source;
remove it before adding this source
These paths referred to the same underlying directory through different operating-system conventions. The marketplace registration did not accept them as the same source.
On September 5, the startup sequence was:
- 05:10:42.619 UTC
Current bundled marketplace files written
- 05:10:42.725 UTC
Marketplace registration rejected
rejected
- 05:10:43.391 UTC
Browser runtime paths selected
The installed desktop code supported the ordering seen in the log. Its marketplace setup first tries to register the prepared source. If registration fails, it returns a failure result or throws before reaching plugin installation and reconciliation.
The browser configuration code still constructs the service path from the app's current component version. In this run, that left the runtime expecting 26.901.41123 while installation was blocked and the cache remained older.
One startup message said bundled_plugins_reconcile_completed after the earlier registration error. Later retries explicitly logged bundled_plugins_reconcile_failed. A completion message on its own was therefore insufficient evidence that the plugins had installed.
The first path change was incomplete
I first changed the registered source from the WSL form to a Windows path with forward slashes:
C:/Users/<user>/.codex/.tmp/bundled-marketplaces/openai-bundled
That was enough for explicit Browser and Chrome installation to succeed. It did not fully repair marketplace reconciliation.
A final check attempted to register the exact Windows source used by the desktop. Codex still returned the “different source” error. Browser access could work after installation while a later automatic plugin update remained blocked by the registration mismatch.
The supported marketplace commands resolved this second detail. Removing and re-adding only the openai-bundled source let Codex persist its own canonical Windows representation:
source = '\\?\C:\Users\<user>\.codex\.tmp\bundled-marketplaces\openai-bundled'
The \\?\ prefix is the Windows extended-length path form. Repeating the same add command then returned alreadyAdded: true. The desktop's next reconciliation accepted the source as well.
| Stored source | Value | Result |
|---|---|---|
| WSL path | /mnt/c/Users/<user>/.codex/.tmp/bundled-marketplaces/openai-bundled | The desktop's Windows source was rejected: already added from a different source.rejected |
| Windows path with forward slashes | C:/Users/<user>/.codex/.tmp/bundled-marketplaces/openai-bundled | Browser and Chrome installed. Registering the desktop's exact Windows source still returned the “different source” error.partial |
| Extended-length form, written by Codex | \\?\C:\Users\<user>\.codex\.tmp\bundled-marketplaces\openai-bundled | The add command returned alreadyAdded: true. The desktop's next reconciliation accepted the source.accepted |
The repair commands
These commands describe the Windows-native repair on this installation. They are not a general instruction to rewrite a Linux-native Codex setup.
Before changing anything, I backed up the shared configuration and confirmed the intended CODEX_HOME, the bundled marketplace directory, and the Browser and Chrome manifests. The local bundle already contained the matching official versions; no package was requested as latest.
In PowerShell, with the intended Windows Codex executable selected:
codex plugin marketplace list
# Use the actual Windows CODEX_HOME if it differs from this default.
$codexConfigRoot = Join-Path $env:USERPROFILE '.codex'
$bundledSource = Join-Path $codexConfigRoot '.tmp\bundled-marketplaces\openai-bundled'
codex plugin marketplace remove openai-bundled --json
codex plugin marketplace add $bundledSource --json
codex plugin add browser@openai-bundled --json
codex plugin add chrome@openai-bundled --json
codex plugin marketplace add $bundledSource --json
codex plugin list --marketplace openai-bundled --json
The sequence above puts the complete source repair before installation. During the investigation, the explicit installations happened after the incomplete forward-slash edit; the remove/add correction followed when the final registration check caught the remaining error.
marketplace remove removed the source registration. This repair did not use plugin remove, delete broad cache directories, replace the whole configuration, or disable the hook.
Both plugin installations reported 26.901.41123, and the service file existed at the exact path requested by the runtime. Comparing the final configuration with the backup showed the source replacement and removal of the old marketplace update metadata. The hook and unrelated settings were preserved.
The runtime needed one more refresh
The first browser retry still returned the earlier missing-module error even though the file now existed. The running JavaScript kernel retained the failed service load.
Resetting that task's kernel and loading the newly installed client cleared the failure. This reset affected the task's JavaScript bindings; it did not require restarting Codex Desktop or Chrome.
The supported browser runtime then selected Chrome through the extension connection. Verification went beyond the connection indicator:
List the existing Chrome tabs.
done
Open a temporary tab at this site's CV page.
done
Read its title and rendered content through the accessibility API.
done
Close the temporary tab.
done
Confirm that the existing Chrome session remained accessible after the final source registration.
done
The desktop logs now showed successful registration followed by reconciliation:
- 06:21:20.983 UTC
bundled_plugins_marketplace_addedadded
- 06:21:21.157 UTC
bundled_plugin_install_skipped_current pluginName=chromealready current
- 06:21:22.623 UTC
bundled_plugins_reconcile_completedcompleted
This time the completion event followed an accepted source registration, and a real browser read had succeeded.
What this repair establishes
The observed failure crossed several boundaries: shared Windows/WSL configuration, marketplace source identity, plugin installation, the service import, and the Chrome connection. The logs and code inspection connected the first four. Opening and reading a page verified the last one.
The repair restored this Windows desktop task's Chrome access. It did not test native Linux plugin discovery with the same shared configuration, prove that every other task had identical live settings, or identify who originally wrote the WSL marketplace source. Future tooling that writes the WSL source back into the shared registration could recreate the conflict.
For this failure, the useful checks were the exact configured service path, the files present in each installation location, the marketplace registration result, and one real browser action. Each answered a different question that the extension's “Connected” label could not answer alone.
My Codex contribution log also links the related marketplace, stale-cache, and runtime-path reproductions.
Sources
This note is based on local configuration, the installed Codex application's code, bundled plugin manifests, September 5 startup logs, CLI installation receipts, and the browser verification described above.
- Part one: fixing the sandboxCwd URI error covers the earlier URI mapping and import hook.
- Part three: finishing the browser task follows the later WSL interoperability, task-path, and Windows process-startup failures through to the completed comparison.
- OpenAI's Codex MCP documentation describes the local MCP configuration used by integrations.
- The Codex agent helped inspect the hook and runtime, trace the registration failure, apply the reviewed repair, and verify Chrome access.