Browser runtime permanently caches empty provider discovery
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What issue are you seeing?
In a Codex CLI-hosted session, the bundled Browser runtime can return
No browser is available even though the Chrome integration is healthy. The
first discovery returns an empty provider list, and that empty list is cached
for the lifetime of the JavaScript/browser runtime. A Chrome provider that
finishes registering afterward is never rediscovered.
Observed API results:
await agent.browsers.getForUrl("https://example.com/")
Error: No browser is available
await agent.browsers.list()
[]
All bundled read-only diagnostics pass:
- Chrome running: exit 0
- supported browser installation detected: exit 0
- ChatGPT/Codex Chrome extension installed and enabled: exit 0
- native-host manifest present, correct host name, and expected origins: exit 0
The local MCP environment contained
NODE_REPL_NATIVE_PIPE_CONNECT_TIMEOUT_MS="1000". Increasing that value is a
local cold-start mitigation, but it does not fix the unrecoverable empty-cache
state once discovery has already occurred.
What steps can reproduce the bug?
Environment:
- Codex CLI 0.150.1
- bundled Browser/Chrome plugin build 26.818.61809
- macOS 26.5.2 (25F84), arm64
- Google Chrome 151.0.7922.174
- Chrome extension 1.2.27268.51612_0
- Start a Codex CLI session with Browser and Chrome plugins enabled and with a
short native-pipe connect timeout. - Initialize the bundled browser runtime once using
setupBrowserRuntime(). - Call
agent.browsers.getForUrl("https://example.com/")before the extension
provider completes registration. - Observe
No browser is available. - Follow bootstrap troubleshooting and call
agent.browsers.list()after the
native host/extension is available. - Observe that it still returns
[]for the rest of the runtime.
The bundled implementation stores browsers=[] after the first refresh, while
getBrowsers() refreshes only when browsers == null. A refresh() method
exists internally but is not exposed through the public browser-client proxy.
What is the expected behavior?
- Do not cache an empty provider discovery permanently.
- Retry empty discovery with bounded backoff, or expose a documented public
refresh()operation that the Browser troubleshooting workflow may call. - Return typed bootstrap diagnostics that distinguish an unavailable in-app
provider, an extension/native-pipe handshake timeout, and an actual extension
or native-host installation defect. - A late provider registration or transient provider disconnect should be
recoverable without restarting the entire Codex session.
Additional information
The supported installation diagnostics passing is important: recommending a
plugin reinstall for this state is both unnecessary and ineffective. No
AppleScript, external browser automation, raw CDP, cookie access, or native-host
repair was used.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the sequence through setupBrowserRuntime(), agent.browsers.getForUrl(), and agent.browsers.list(), then trace getBrowsers() and the internal refresh() behavior in the bundled Browser runtime. Check how the public browser-client proxy handles late registration and transient disconnects. Done means empty discovery can recover without restarting the Codex session and bootstrap failures distinguish the reported diagnostic cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100