codex-wsl-windows-marketplace-conflict.md — 10 min read

2026-09-0510 min readManuel ParraInvestigation

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.

  • Codex
  • WSL
  • Windows
  • Chrome
  • MCP
  • Debugging
On this page · 9 sections
  1. 01The failure happened before Chrome
  2. 02Why was the task loading code from a cache?
  3. 03Was the import hook changing the path?
  4. 04The startup log exposed the installation failure
  5. 05The first path change was incomplete
  6. 06The repair commands
  7. 07The runtime needed one more refresh
  8. 08What this repair establishes
  9. 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.js

Where 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

  1. Remove and re-add only the openai-bundled marketplace source, so Codex stores its own Windows form of the path.

    codex plugin marketplace remove openai-bundled --jsoncodex plugin marketplace add $bundledSource --json

    The repair commands

  2. Install the Browser and Chrome plugins.

    codex plugin add browser@openai-bundled --jsoncodex plugin add chrome@openai-bundled --json

  3. Reset the task's JavaScript kernel and load the newly installed client.

    The runtime needed one more refresh

Tried first

Desktop app

The desktop app was version 26.901.5003.0.

Bundled Browser component

Its bundled Browser component identified itself as 26.901.41123.

expected

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 26.727.40816.

present

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:

Path shapetext
<CODEX_HOME>/plugins/cache/<marketplace>/<plugin>/<version>/scripts/browser-service.mjs

There were three copies or destinations to distinguish:

  1. The application bundle contained the shipped Browser plugin and its service file.

    current files
  2. The prepared marketplace directory, under .tmp/bundled-marketplaces/openai-bundled, contained the current files that the plugin installer could consume.

    current files
  3. installation stepfailed

    The installed plugin cache, under plugins/cache/openai-bundled/browser, contained the older installed version.

    older version
The current files had reached the first two locations. They had not reached the third.

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:

WSL pathjs
await import("/mnt/c/work/plugin/browser-client.mjs")

becomes:

file URIjs
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:

config.toml · registered source (WSL path)toml
[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:

Windows desktop triedtext
C:\Users\<user>\.codex\.tmp\bundled-marketplaces\openai-bundled

The log recorded the rejection:

Log · rejectedtext
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:

  1. 05:10:42.619 UTC

    Current bundled marketplace files written

  2. 05:10:42.725 UTC

    Marketplace registration rejected

    rejected

  3. 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:

First change · incompletetext
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:

Canonical source Codex kepttoml
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.

Three spellings of the same marketplace source, and what registration did with each
Stored sourceValueResult
WSL path/mnt/c/Users/<user>/.codex/.tmp/bundled-marketplaces/openai-bundledThe desktop's Windows source was rejected: already added from a different source.rejected
Windows path with forward slashesC:/Users/<user>/.codex/.tmp/bundled-marketplaces/openai-bundledBrowser 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-bundledThe add command returned alreadyAdded: true. The desktop's next reconciliation accepted the source.accepted
This was why a valid filesystem path was not enough: registration also depended on the stored representation used to identify the source.

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:

PowerShell · repair commandspowershell
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:

  1. List the existing Chrome tabs.

    done

  2. Open a temporary tab at this site's CV page.

    done

  3. Read its title and rendered content through the accessibility API.

    done

  4. Close the temporary tab.

    done

  5. Confirm that the existing Chrome session remained accessible after the final source registration.

    done

The desktop logs now showed successful registration followed by reconciliation:

  1. 06:21:20.983 UTC

    bundled_plugins_marketplace_added

    added

  2. 06:21:21.157 UTC

    bundled_plugin_install_skipped_current pluginName=chrome

    already current

  3. 06:21:22.623 UTC

    bundled_plugins_reconcile_completed

    completed

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.