fix(browser): Browser Use cannot connect to IAB from Node REPL on macOS

Open 💬 18 comments Opened May 1, 2026 by elitan
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What issue are you seeing?

Browser Use is installed and the in-app browser is open, but Browser bootstrap fails from the discovered Node REPL tool:

Failed to connect to browser-use backend "iab"

This is on macOS, not Windows/MSIX.

Environment

Codex Desktop: 26.429.20946
codex-cli in app bundle: 0.128.0-alpha.1
Browser Use plugin: openai-bundled/browser-use/0.1.0-alpha1
OS: macOS

Feature state from app-bundled CLI:

apps              true
browser_use       true
computer_use      true
in_app_browser    true
plugins           true
js_repl           removed false

What I verified

The IAB socket exists under:

/tmp/codex-browser-use/*.sock

From normal app-bundled Node, JSON-RPC getInfo with the current session_id and turn_id succeeds and returns:

type: iab
name: Codex In-app Browser
version: 26.429.20946

From mcp__node_repl__js, the same socket connects and writes, but no response is received before timeout. Browser bootstrap then fails with:

Failed to connect to browser-use backend "iab"

Expected behavior

When Browser Use is enabled and the in-app browser is open, the discovered Node REPL tool should be able to initialize Browser Use against the IAB backend.

Notes

This looks different from the Windows helper-binary/path issues. The IAB backend exists and responds from normal Node, but not from the Node REPL tool used by the Browser skill.

View original on GitHub ↗

18 Comments

github-actions[bot] contributor · 2 months ago

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

  • #20248
  • #20579
  • #19463

Powered by Codex Action

talhasarit · 2 months ago

I can reproduce a related macOS failure, with an extra subagent-specific angle.

Environment:

  • Codex Desktop: 26.429.30905, bundle 2345
  • codex-cli: 0.128.0-alpha.1
  • macOS: 15.7.5, arm64
  • Browser Use plugin: openai-bundled/browser-use/0.1.0-alpha1
  • browser_use, in_app_browser, plugins, multi_agent, and tool_search are enabled

Repro:

  1. Spawn a built-in qa_reviewer subagent.
  2. In the subagent, load the Browser Use skill and run the normal bootstrap:

``js
const { setupAtlasRuntime } = await import("<browser-use plugin>/scripts/browser-client.mjs");
await setupAtlasRuntime({ globals: globalThis, backend: "iab" });
``

  1. Target was a local HTTP page, e.g. http://127.0.0.1:51234/README.md.

Expected:
The subagent should be able to attach to the Codex in-app browser backend and inspect/navigate the tab.

Actual:
Bootstrap fails before tab creation:

Failed to connect to browser-use backend "iab". No Codex IAB backends were discovered.
Discovery diagnostics: listedPipes=7, candidates=9, browsers=0, iabBrowsers=0, failures=["discovered/get-info/string", ...], pipeListingError=none.

Additional diagnostics:

  • The parent thread initially could use Browser Use against the same local HTTP target.
  • qa_reviewer, default subagent, and forked-context subagent all failed with the same IAB discovery error.
  • Parent and subagent Node REPL metadata had different x-codex-turn-metadata session/turn IDs.
  • Attempting to bridge the parent metadata into the subagent is not possible from user code: nodeRepl.requestMeta is getter-only / frozen, and assignment fails with:

``text
Cannot assign to read only property 'session_id' of object '[object Object]'
``

  • After a later turn/reset, fresh parent Browser Use bootstrap also failed with the same IAB discovery error; a stale parent Browser Use object produced:

``text
Browser turn does not belong to this IAB pipe
``

This looks like the IAB bridge/session ownership is not available consistently to the Node REPL runtime, and subagent sessions appear especially unable to inherit or attach to the parent thread's in-app browser backend.

tho-stack · 2 months ago

Adding a more specific repro/signature from another macOS Desktop session. This looks like an IAB route/turn ownership mismatch rather than a missing socket or localhost permission issue.

Environment:

  • macOS
  • Codex Desktop: 26.429.30905, build 2345
  • app-bundled CLI: codex-cli 0.128.0-alpha.1
  • Browser Use plugin: openai-bundled/browser-use/0.1.0-alpha1
  • In-app browser open
  • /tmp/codex-browser-use/*.sock sockets exist and are owned by the live Codex app process

Observed behavior:

  • One Desktop thread initially had working Browser Use, then later Browser Use stopped working in the same thread.
  • Another Desktop thread never got a usable Browser Use backend.
  • A third Desktop thread in the same app process works against the same in-app browser page, so the plugin/socket is not globally broken.

Failure from Browser Use bootstrap in broken threads:

Failed to connect to browser-use backend "iab". No Codex IAB backends were discovered.
Discovery diagnostics: listedPipes=6, candidates=8, browsers=0, iabBrowsers=0,
failures=["discovered/get-info/string", ...]

One retry also surfaced the raw ownership error:

Browser turn does not belong to this IAB pipe

Key Desktop app log signature from the thread that worked first and then broke:

2026-05-04T06:16:11.371Z info [AppServerConnection] response_routed ... method=turn/start ... conversationId=019df185-2079-7370-9386-6aaf75c2b739 ...
2026-05-04T06:16:11.389Z info [browser-session-registry] IAB_LIFECYCLE captured turn route conversationId=019df185-2079-7370-9386-6aaf75c2b739 ownerWebContentsId=1 turnId=019df1a1-4547-72a1-8bc6-e4353bab063e windowId=1
2026-05-04T06:16:11.515Z warning [electron-message-handler] Synthesizing missing turn for incoming event conversationId=019df185-2079-7370-9386-6aaf75c2b739 turnId=ee9efbe9-09a8-499a-a0c6-737193c015bd

Later in the same app process a fresh turn in another thread succeeds because the captured Browser Use route and the Node REPL turn metadata agree:

2026-05-04T07:16:10.629Z info [browser-session-registry] IAB_LIFECYCLE captured turn route conversationId=019df1ce-ffac-78a3-88f3-dcffdd196c4f ownerWebContentsId=1 turnId=019df1d8-30db-7910-aed7-eb1eef9c31bf windowId=1
2026-05-04T07:17:18.946Z info [browser-sidebar-manager] IAB_LIFECYCLE syncing browser use active state conversationId=019df1ce-ffac-78a3-88f3-dcffdd196c4f isActive=true ownerWebContentsId=1 turnId=019df1d8-30db-7910-aed7-eb1eef9c31bf windowId=1

There is also a second failure mode after the browser pane/guest is torn down:

2026-05-04T06:48:26.642Z warning [browser-sidebar-manager] IAB_LIFECYCLE browser use open wait timed out conversationId=019df185-2079-7370-9386-6aaf75c2b739 ownerWebContentsId=1
2026-05-04T06:48:26.642Z warning [browser-sidebar-manager] IAB_LIFECYCLE browser use open wait rejected conversationId=019df185-2079-7370-9386-6aaf75c2b739 errorMessage="No active Codex browser pane available" ownerWebContentsId=1

What I think is happening:

The packaged Desktop app has a strict per-turn IAB ownership check. In the installed app.asar, requireBrowserUseSession rejects if canServeRoute returns false:

if (!this.canServeRoute(r)) throw Error(`Browser turn does not belong to this IAB pipe`);

And the route lookup is keyed by conversationId + turnId:

let n = this.turnRoutes.get(XC(e));

So if Desktop captures an IAB route for turn 019df1a1-... but the incoming/synthesized turn or Node REPL Browser Use metadata uses ee9efbe9-..., getInfo throws before returning IAB metadata. The Browser Use client then reports browserCount=0 / iabBrowsers=0 with discovered/get-info/string, even though the socket exists.

tho-stack · 2 months ago

Update: local Desktop hotfix tested

Adding a follow-up to my earlier comment: I locally hotpatched the installed Codex Desktop app to test the suspected Browser Use / in-app-browser route mismatch.

What was patched

The patch was applied to the installed Electron bundle:

/Applications/Codex.app/Contents/Resources/app.asar

Inside that ASAR, the changed code lives in the bundled main process JS entry:

.vite/build/main-DlFGMsC6.js

The relevant guard is the Browser Use route ownership check, canServeTurnForBrowserRoute.

Before, the check required an exact {conversationId, turnId} route entry:

canServeTurnForBrowserRoute(e, t) {
  let n = this.turnRoutes.get(XC(e)); // exact conversationId:turnId key
  return n == null || this.delegate?.isWindowAlive(n.windowId) !== true
    ? false
    : n.conversationId === t.conversationId && n.windowId === t.windowId;
}

The local hotfix changed it to tolerate a missing exact per-turn route if there is still an active route for the same {conversationId, windowId}:

canServeTurnForBrowserRoute(e, t) {
  let n = this.turnRoutes.get(XC(e));
  return e.conversationId === t.conversationId &&
    (n
      ? n.windowId === t.windowId
      : this.hasActiveTurnRouteForBrowserRoute(t));
}

Why this matches the observed failure

The failing sessions looked like a turn-id mismatch rather than global Browser Use corruption:

  • Browser Use worked in one Desktop thread.
  • Browser Use failed in two other Desktop threads.
  • One of the broken threads worked initially, then later stopped.
  • Logs showed Desktop captured a Browser Use route for one turnId, but later incoming/synthesized Browser Use metadata used another turnId.
  • The existing guard rejected that even though the active browser route still belonged to the same conversation and window.

Other IAB routing logs show the backend host keyed by:

routeKey=windowId:conversationId

So the strict exact-turn check seems narrower than the rest of the Browser Use host routing model.

Safety of the tested change

The hotfix does not remove the conversation/window ownership boundary:

  • It still rejects cross-conversation Browser Use access.
  • If an exact turn route exists, it still requires the same window.
  • Only when the exact turn route is missing does it fall back to hasActiveTurnRouteForBrowserRoute(t).
  • That fallback still checks for an active route for the same {conversationId, windowId}.

Result after patching

After the hotpatch, both formerly broken conversations started resolving Browser Use routes instead of failing discovery.

For conversation 019df185-2079-7370-9386-6aaf75c2b739:

IAB_LIFECYCLE captured turn route conversationId=019df185-2079-7370-9386-6aaf75c2b739 turnId=019df251-bbaf-7b52-9dd6-624ba1d50798 windowId=1
IAB_LIFECYCLE created browser use host conversationId=019df185-2079-7370-9386-6aaf75c2b739 routeKey=1:019df185-2079-7370-9386-6aaf75c2b739 windowId=1
IAB_LIFECYCLE resolved browser use route conversationId=019df185-2079-7370-9386-6aaf75c2b739 turnId=019df251-bbaf-7b52-9dd6-624ba1d50798 windowId=1

For conversation 019df185-d1d3-7b32-8035-369a6b37fb5f:

IAB_LIFECYCLE captured turn route conversationId=019df185-d1d3-7b32-8035-369a6b37fb5f turnId=019df253-e19a-72d2-bb7e-cba73c00492b windowId=1
IAB_LIFECYCLE created browser use host conversationId=019df185-d1d3-7b32-8035-369a6b37fb5f routeKey=1:019df185-d1d3-7b32-8035-369a6b37fb5f windowId=1
IAB_LIFECYCLE iab createTab mapped page to tab conversationId=019df185-d1d3-7b32-8035-369a6b37fb5f tabId=1 turnId=019df253-e19a-72d2-bb7e-cba73c00492b

Post-hotpatch checks in the fresh Desktop logs:

  • no Browser turn does not belong to this IAB pipe
  • no discovered/get-info/string
  • no browserCount=0 / iabBrowsers=0
  • no No active Codex browser pane available
  • no Electron ASAR integrity failures after the bundle integrity metadata was updated

Local Electron packaging note

Because this was a direct local patch to app.asar, launching the modified app required updating Electron/macOS integrity metadata as well. I'll leave those details out of here.

One of these should fix the underlying issue cleanly:

  • Make canServeTurnForBrowserRoute tolerate a missing exact {conversationId, turnId} route if there is an active Browser Use route for the same {conversationId, windowId}.
  • Or, when Desktop synthesizes a missing turn, alias/update turnRoutes so the Browser Use request metadata and route registry use the same turnId.
  • Also surface the raw ownership error in Browser Use discovery instead of collapsing it into discovered/get-info/string.
tho-stack · 2 months ago

And that wasn't enough, the moment more than 1 session uses browser use or makes a turn it errors.

What i did so far - it seems to work for now. running browser_use in 2 sessions in parallel.

Follow-up: local IAB hotfix code changes

I narrowed this down to two related Browser Use / IAB route problems:

  1. The renderer could start or steer a turn without re-capturing the Browser Use route for the returned turn id.
  2. The main process required an exact (conversationId, turnId) route lookup, but some failing turns captured the route under one turn id and then Browser Use requested the same IAB session under another turn id in the same conversation.

I applied a local hotfix to:

/Applications/Codex.app/Contents/Resources/app.asar

The modified bundled files inside the ASAR are:

.vite/build/main-DlFGMsC6.js
webview/assets/app-server-manager-signals-DBUY-BE0.js

1. Main process: resolve Browser Use route with same-conversation fallback

File:

.vite/build/main-DlFGMsC6.js

Before, resolveBrowserRoute(...) threw immediately when the exact turn route was missing:

resolveBrowserRoute(browserSession) {
  const route = this.turnRoutes.get(routeKey(browserSession));

  if (route == null) {
    logger.warning("IAB_LIFECYCLE missing browser use turn route", {
      safe: browserSession,
      sensitive: {},
    });

    throw new Error(
      `No Codex browser route captured for browser session ${browserSession.conversationId} turn ${browserSession.turnId}`,
    );
  }

  const windowRoute = {
    conversationId: route.conversationId,
    windowId: route.windowId,
  };

  this.assertWindowAlive(windowRoute);

  logger.info("IAB_LIFECYCLE resolved browser use route", {
    safe: {
      conversationId: route.conversationId,
      ownerWebContentsId: route.ownerWebContentsId,
      turnId: route.turnId,
      windowId: route.windowId,
    },
    sensitive: {},
  });

  return windowRoute;
}

After, it first tries the exact route, then falls back to any live route for the same conversation:

resolveBrowserRoute(browserSession) {
  let route = this.turnRoutes.get(routeKey(browserSession));

  if (route == null) {
    for (const candidateRoute of this.turnRoutes.values()) {
      if (
        candidateRoute.conversationId === browserSession.conversationId &&
        this.delegate?.isWindowAlive(candidateRoute.windowId) === true
      ) {
        route = candidateRoute;
        break;
      }
    }
  }

  if (route == null) {
    logger.warning("IAB_LIFECYCLE missing browser use turn route", {
      safe: browserSession,
      sensitive: {},
    });

    throw new Error(
      `No Codex browser route captured for browser session ${browserSession.conversationId} turn ${browserSession.turnId}`,
    );
  }

  const windowRoute = {
    conversationId: route.conversationId,
    windowId: route.windowId,
  };

  this.assertWindowAlive(windowRoute);

  logger.info("IAB_LIFECYCLE resolved browser use route", {
    safe: {
      conversationId: route.conversationId,
      ownerWebContentsId: route.ownerWebContentsId,
      turnId: route.turnId,
      windowId: route.windowId,
    },
    sensitive: {},
  });

  return windowRoute;
}

2. Main process: allow same-conversation active route when exact turn route is missing

File:

.vite/build/main-DlFGMsC6.js

Before:

canServeTurnForBrowserRoute(browserSession, targetRoute) {
  const route = this.turnRoutes.get(routeKey(browserSession));

  if (route == null || this.delegate?.isWindowAlive(route.windowId) !== true) {
    return false;
  }

  return (
    route.conversationId === targetRoute.conversationId &&
    route.windowId === targetRoute.windowId
  );
}

After:

canServeTurnForBrowserRoute(browserSession, targetRoute) {
  const route = this.turnRoutes.get(routeKey(browserSession));

  return (
    browserSession.conversationId === targetRoute.conversationId &&
    (route
      ? route.windowId === targetRoute.windowId
      : this.hasActiveTurnRouteForBrowserRoute(targetRoute))
  );
}

This keeps the fallback scoped to the same conversation instead of allowing cross-thread ownership.

3. Renderer: capture Browser Use route after turn/steer

File:

webview/assets/app-server-manager-signals-DBUY-BE0.js

Before:

async function steerTurn(appServer, threadId, input, expectedTurnId, metadata) {
  const request = {
    threadId,
    input,
    expectedTurnId,
    responsesapiClientMetadata: metadata,
  };

  return appServer.sendRequest("turn/steer", request, {
    timeoutMs: TURN_TIMEOUT_MS,
  });
}

After:

async function steerTurn(appServer, threadId, input, expectedTurnId, metadata) {
  const request = {
    threadId,
    input,
    expectedTurnId,
    responsesapiClientMetadata: metadata,
  };

  const response = await appServer.sendRequest("turn/steer", request, {
    timeoutMs: TURN_TIMEOUT_MS,
  });

  appServer.captureBrowserUseTurnRoute(threadId, response.turnId);

  return response;
}

Verification after patch

Finally, after restarting the app, Browser Use attached successfully through the iab backend and basic browser API calls succeeded:

setupAtlasRuntime({ backend: "iab" }): success
tab.url(): success
tab.title(): success
tab.playwright.domSnapshot(): success
tab.dev.logs(): success

There are also other unrelated issues with the IAB not starting up fast enough etc. - but once running this seems to work, so far.

johnsilvavlogs · 2 months ago

Adding controlled evidence from another macOS Codex Desktop session. This looks like the same IAB route/turn ownership class of failure, with an additional lifecycle symptom: after the IAB route is lost, the in-app browser can remain visually open while Browser Use reports no usable IAB backend or hangs on tab commands.

Environment:

  • Codex Desktop 26.429.30905, build 2345
  • macOS 26.3 build 25D125
  • Browser Use plugin openai-bundled/browser-use/0.1.0-alpha1
  • Backend requested: iab

Original failure signature from a private session log, sanitized to avoid workflow/account details:

2026-05-04T19:00:22.972Z  Browser turn does not belong to this IAB pipe
2026-05-04T19:00:29.630Z  Browser turn does not belong to this IAB pipe
2026-05-04T19:00:39.211Z  Failed to connect to browser-use backend "iab".
                           No Codex IAB backends were discovered.
                           listedPipes=11, candidates=13, browsers=0, iabBrowsers=0,
                           pipeListingError=none

Later retries in the same broad app state repeated browsers=0, iabBrowsers=0.

Controlled localhost reproduction matrix, avoiding external accounts:

  • attach_initial_iab: passed. Browser Use attached to a localhost page and could inspect/interact.
  • reattach_after_js_reset: passed. Same IAB tab stayed commandable.
  • modal/file-input/popup/DOM-churn/navigation stress page: passed. Page complexity alone did not reproduce the loss.
  • reattach after stress + js_reset: passed.
  • closing the only Browser Use tab via API: failed. tabs.new() returned No active Codex browser pane available.
  • after that broken state, a fresh setup/nameSession could return, but tabs.list() and tabs.selected() hung until locally bounded by timeouts, and tabs.new() still returned No active Codex browser pane available.
  • a side-agent/session during the broken state saw No Codex IAB backends were discovered, with listedPipes=18, candidates=20, browsers=0, iabBrowsers=0.

Local code observations from the installed app/client:

  • Browser Use discovery accepts IAB candidates only when info.type === "iab" and metadata.codexSessionId matches the current session_id.
  • Every command is stamped with session_id and turn_id.
  • The installed app bundle contains requireBrowserUseSession(), which throws Browser turn does not belong to this IAB pipe when the current turn is rejected by the app-side route check.
  • The Browser Use client nulls its socket on native pipe close, but does not clearly notify close listeners or reject pending JSON-RPC requests, so tabs.list() / tabs.selected() can hang after the backend disappears.
  • Setup cache hits do not appear to ping/liveness-check the cached context before reuse.
  • Discovery diagnostics collapse candidate failures to strings like discovered/get-info/string, which hides whether each candidate was stale, the wrong session, the wrong type, missing metadata, or rejecting the current turn.

Current root-cause hypothesis:

  1. The app-side IAB route/turn ownership can be invalidated after a long session or pane/tab lifecycle transition.
  2. The visible in-app browser pane and the commandable native pipe/backend registration can diverge.
  3. The client does not have a strong rebind/reopen path after transport loss or route mismatch, and its diagnostics make stale/rejected candidates look like there are simply zero IAB browsers.

Recommended fixes/regression tests:

  • On unexpected native pipe close, reject pending RPCs and notify listeners.
  • Ping cached IAB context before reuse; dispose and rediscover on failure.
  • Add bounded timeouts around discovery and tab commands.
  • Add a fresh discovery/rebind loop after Browser turn does not belong to this IAB pipe and after No Codex IAB backends were discovered.
  • Return precise pane lifecycle errors instead of hanging when the final IAB tab/pane is closed.
  • Improve diagnostics so each candidate includes path label, getInfo result/error, returned type, session match/mismatch, and rejection reason.
  • Regression cases: attach_initial_iab, reattach_after_js_reset, reattach_after_transport_loss, close_last_tab_recovery, turn_mismatch_rebind, and discovery_diagnostics.

Related fallback issue after this failure class: https://github.com/openai/codex/issues/21068

a252937166 · 2 months ago

Adding another macOS Desktop reproduction with a slightly different lifecycle signature: a full local cleanup/restart temporarily restores Browser Use, but the IAB route registry breaks again within a few minutes.

Environment:

Codex Desktop: 26.429.30905
App server: 0.128.0-alpha.1
Browser Use plugin: openai-bundled/browser-use/0.1.0-alpha1
OS: macOS 15.4.1 (24E263)
Backend requested: iab
Target URL: http://localhost:1420/home and http://127.0.0.1:1420/home

Cleanup/restart performed before this repro:

osascript -e 'quit app "Codex"'
pkill -f '/Applications/Codex.app/Contents/Resources/codex app-server'
pkill -f '/Applications/Codex.app/Contents/Resources/node_repl'
pkill -f '/Applications/Codex.app/Contents/Resources/node --experimental-vm-modules'
rm -rf /tmp/codex-browser-use
rm -f /tmp/codex-browser-use.sock /tmp/codex-browser-use-iab.sock
rm -rf "$HOME/Library/Application Support/Codex/Partitions/codex-browser-app"
rm -f "$HOME/Library/Application Support/Codex/browser-sidebar-local-servers.json"

After the restart, the first Browser Use attempt could work briefly. A later attempt against the same local URL failed before navigation with:

Failed to connect to browser-use backend "iab". No Codex IAB backends were discovered.
Discovery diagnostics: listedPipes=3, candidates=5, browsers=0, iabBrowsers=0, failures=["discovered/timeout", ...]

The local target was not the problem:

http://127.0.0.1:1420/home -> 200 OK

The IAB sockets also existed and were owned by the live Codex process:

/tmp/codex-browser-use/1289cba4-8ad7-416a-b89f-06eb31f0d727.sock
/tmp/codex-browser-use/a3f5b71d-8cf1-450e-aa76-b28768ab01ca.sock
/tmp/codex-browser-use/2a397e04-681f-4147-898d-d19b6fbc71f7.sock

Codex PID 75029 held all three sockets via lsof.

Relevant desktop log sequence from the same run:

2026-05-05T12:50:41.312Z IAB_LIFECYCLE registered browser sidebar thread conversationId=new-conversation
2026-05-05T12:50:41.315Z browser-use native pipe listening pipePath=/tmp/codex-browser-use/1289cba4-8ad7-416a-b89f-06eb31f0d727.sock
2026-05-05T12:50:46.451Z Received turn/started for unknown conversation conversationId=019df830-e221-7d42-a949-0d402ead8c21

2026-05-05T12:50:55.568Z IAB_LIFECYCLE registered browser sidebar thread conversationId=019df6b1-8645-7842-ab69-422fc8ceb427
2026-05-05T12:50:55.572Z browser-use native pipe listening pipePath=/tmp/codex-browser-use/a3f5b71d-8cf1-450e-aa76-b28768ab01ca.sock

2026-05-05T12:51:28.292Z IAB_LIFECYCLE registered browser sidebar thread conversationId=019de417-05c4-7531-87b8-715d55304120
2026-05-05T12:51:28.297Z browser-use native pipe listening pipePath=/tmp/codex-browser-use/2a397e04-681f-4147-898d-d19b6fbc71f7.sock

2026-05-05T12:52:00.620Z IAB_LIFECYCLE captured turn route conversationId=019df6b1-8645-7842-ab69-422fc8ceb427 turnId=019df832-03c5-7851-98c9-d4902e9b9a24
2026-05-05T12:52:36.027Z IAB_LIFECYCLE renderer removed browser sidebar webview conversationId=019df6b1-8645-7842-ab69-422fc8ceb427 tabType=new-tab-page
2026-05-05T12:52:51.521Z IAB_LIFECYCLE ended browser use turn route conversationId=019df6b1-8645-7842-ab69-422fc8ceb427 turnId=019df832-03c5-7851-98c9-d4902e9b9a24

2026-05-05T12:53:18.770Z IAB_LIFECYCLE captured turn route conversationId=019de417-05c4-7531-87b8-715d55304120 turnId=019df833-3514-7603-acb8-247d89f56339
2026-05-05T12:53:25.679Z Received turn/started for unknown conversation conversationId=019df833-5015-7f60-9321-fff98d12185a

Interpretation: this does not look like missing socket files, a localhost permission issue, or proxy interference. The sockets are created and held by Codex, but after route/webview lifecycle churn the Browser Use runtime can no longer get a usable IAB backend and all discovered pipe probes time out. The repeated Received turn/started for unknown conversation entries seem related to the route ownership mismatch described in #21167.

alario-tang · 2 months ago

Adding another macOS Desktop reproduction after a full Codex App restart. This still fails after restarting the app and retrying the official Browser Use bootstrap.

Environment:

Codex Desktop: 26.429.61741, build 2429
App-bundled codex-cli: 0.128.0-alpha.1
Browser Use plugin: openai-bundled/browser-use/0.1.0-alpha1
Backend requested: iab
OS: macOS 26.4.1, arm64

Repro in the Node REPL tool:

if (!globalThis.agent) {
  const { setupAtlasRuntime } = await import('/Users/harrytang/.codex/plugins/cache/openai-bundled/browser-use/0.1.0-alpha1/scripts/browser-client.mjs');
  const backend = 'iab';
  await setupAtlasRuntime({ globals: globalThis, backend });
}
await agent.browser.nameSession('final iab retry');
if (typeof tab === 'undefined') {
  globalThis.tab = await agent.browser.tabs.new();
}

Actual result:

Failed to connect to browser-use backend "iab". No Codex IAB backends were discovered. Discovery diagnostics: listedPipes=2, candidates=4, browsers=0, iabBrowsers=0, failures=["discovered/timeout","discovered/timeout","legacy-iab/timeout","legacy-chrome/timeout"], pipeListingError=none.

The sockets exist and are owned by the live Codex process:

/tmp/codex-browser-use/0963b858-8fe8-4a91-9e4f-583a8c3af41c.sock
/tmp/codex-browser-use/cbc7f30e-f255-41ba-b1a0-ab520207483b.sock

Codex PID 35680 holds both sockets via lsof.

Fresh Desktop log signature from the same post-restart run:

2026-05-06T04:20:15.307Z info [electron-message-handler] Features enabled enabledFeatures="enable_request_compression, collaboration_modes, personality, request_rule, image_generation, image_detail_original, workspace_dependencies, guardian_approval, workspace_owner_usage_nudge, apps, plugins, tool_search, tool_call_mcp_elicitation"
2026-05-06T04:20:15.844Z error [electron-message-handler] Request failed conversationId=none durationMs=513 error={"code":-32600,"message":"unsupported feature enablement `workspace_dependencies`: currently supported features are apps, memories, plugins, remote_control, tool_search, tool_suggest, tool_call_mcp_elicitation"} method=experimentalFeature/enablement/set
2026-05-06T04:20:15.845Z error [electron-message-handler] Failed to sync experimental feature enablement error={"code":-32600,"message":"unsupported feature enablement `workspace_dependencies`: currently supported features are apps, memories, plugins, remote_control, tool_search, tool_suggest, tool_call_mcp_elicitation"} hostId=local
2026-05-06T04:20:15.845Z info [browser-use-native-pipe-server] browser-use native pipe listening pipePath=/tmp/codex-browser-use/cbc7f30e-f255-41ba-b1a0-ab520207483b.sock
2026-05-06T04:20:21.596Z info [browser-use-native-pipe-server] browser-use native pipe listening pipePath=/tmp/codex-browser-use/0963b858-8fe8-4a91-9e4f-583a8c3af41c.sock
2026-05-06T04:20:21.815Z info [BrowserUseThreadConfig] browser_use_runtime_paths_selected codexCliPath=/Applications/Codex.app/Contents/Resources/codex nodePath=/Applications/Codex.app/Contents/Resources/node nodeReplPath=/Applications/Codex.app/Contents/Resources/node_repl nodeVersionValue=v24.14.0 platform=darwin

This looks like the IAB/native pipe is present, but the handshake/getInfo path times out. The workspace_dependencies feature sync failure is reproducible immediately after app startup and may be related or at least a useful correlated signature.

dingshanliang · 2 months ago

Adding a related Chrome backend reproduction from macOS Desktop. This is not the IAB backend, but it appears to hit the same Browser Use native-pipe/bootstrap class of failure: setupAtlasRuntime() can hang before any browser command is issued.

Environment:

Codex Desktop: 26.506.21252
App server: 0.129.0-alpha.15
Chrome plugin: openai-bundled/chrome/0.1.7
Codex Chrome Extension: 1.1.4_0
Google Chrome: 147.0.7727.138
macOS: darwin arm64
Backend requested: extension / chrome

Initial user request was simply to open GitHub through the Chrome plugin. GitHub itself was reachable from the machine:

curl -I https://github.com/ -> HTTP/2 200

Chrome/extension/native host checks all passed:

Google Chrome running: yes
Codex Chrome Extension installed: true
registered: true
enabled: true
NativeMessagingHost correct: true
manifest path: ~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.openai.codexextension.json
host path: ~/.codex/plugins/cache/openai-bundled/chrome/latest/extension-host/macos/arm64/extension-host
allowed origin: chrome-extension://hehggadaopoacecdllhhajmbjkdcmajg/

The normal Chrome plugin bootstrap repeatedly hung until the Node REPL tool call timeout:

const { setupAtlasRuntime } = await import(
  "/Users/ericding/.codex/plugins/cache/openai-bundled/chrome/0.1.7/scripts/browser-client.mjs"
);
await setupAtlasRuntime({ globals: globalThis });
globalThis.browser = await agent.browsers.get("extension");

Actual result:

js execution timed out; kernel reset, rerun your request

Additional controlled checks:

  • nodeRepl.write('node_repl_ok') succeeds, so the Node REPL transport itself is alive.
  • Importing browser-client.mjs alone succeeds quickly.
  • The hang occurs inside setupAtlasRuntime().
  • A full cleanup was performed: terminated Google Chrome, ChatGPT Atlas, and stale extension-host processes; removed every file under /tmp/codex-browser-use; then started only Google Chrome via the plugin helper.
  • After clean Chrome startup, /tmp/codex-browser-use contained exactly one fresh Chrome extension-host socket:
/tmp/codex-browser-use/91ba3440-a5fc-4b78-a87b-d90d589345a1.sock
extension-host PID 21221 held that socket

Even in that clean state, setupAtlasRuntime({ globals }) still timed out after 45s.

As a control, removing the only visible socket so that /tmp/codex-browser-use was empty still caused setupAtlasRuntime() to hang for 15s instead of quickly returning a “no backend discovered” diagnostic. That suggests at least one pre-discovery initialization path can hang independently of the socket scan.

Relevant Desktop log signatures from the same session:

primary_runtime_install_failed errorMessage="fetch failed"
Update aborted ... NSURLErrorDomain Code=-1009
unsupported feature enablement `workspace_dependencies`
browser-use native pipe listening pipePath=/tmp/codex-browser-use/...

Network checks from shell showed:

curl -I https://chatgpt.com/backend-api/me -> HTTP/2 403 cf-mitigated: challenge
curl -I https://ab.chatgpt.com/v1 -> HTTP/2 403
curl -I https://github.com/ -> HTTP/2 200

Hypothesis:

  1. setupAtlasRuntime() should not be able to hang indefinitely during ambient telemetry/account/feature initialization or native-pipe discovery.
  2. Discovery should use bounded per-candidate timeouts and return structured diagnostics for each backend candidate.
  3. The Chrome extension backend path should surface whether it is stuck before pipe discovery, during native-pipe connect, or during getInfo.
  4. Ambient network failures / Cloudflare challenges against OpenAI endpoints should not block local Chrome backend discovery or opening a normal page.

Suggested fixes/regression coverage:

  • Add a bounded timeout around the pre-discovery initialization path inside setupAtlasRuntime().
  • Avoid awaiting nonessential telemetry/account/Statsig calls before local backend discovery, or make them fire-and-forget with failure isolation.
  • Add per-socket connect and getInfo timeouts for both IAB and extension backends.
  • Include candidate path, backend type if known, phase (pre-discovery, pipe-list, pipe-connect, getInfo), and raw error/timeout in diagnostics.
  • Regression: fresh Chrome extension backend with a single native-host socket must either connect or fail with a bounded diagnostic, never hang the Node REPL call.
elitan · 2 months ago

this was fixed for me btw by updating codex

willgpate · 2 months ago

Adding a fresh macOS Desktop reproduction from a newer build. This looks related to the Browser Use reliability class here, but the failure is now one layer earlier than IAB route discovery: the sandboxed node_repl kernel cannot start at all.

Environment:

Codex Desktop: 26.513.31313, build 2867
App-bundled codex-cli: codex-cli 0.131.0-alpha.9
Browser plugin: openai-bundled/browser/0.1.0-alpha2
Chrome plugin: openai-bundled/chrome/0.1.7
OS: macOS 26.4.1 (25E253), Darwin 25.4.0, arm64
Workspace: <redacted-user-home>/Documents/Codex/2026-05-16/debug-and-resolve-why-browser-use

Observed original failure:

  • Browser/Node bridge processes were being reused across chats.
  • Current workspace was:

<redacted-user-home>/Documents/Codex/2026-05-16/debug-and-resolve-why-browser-use

  • Active stale bridge/kernel processes were running with:

<redacted-user-home>/Documents/Codex/2026-05-15/investigate-cloudflare-preview-boot-failure-for

  • Killing those stale processes was not durable before app restart: rediscovery could respawn against the old workspace.

After fully quitting and reopening Codex:

Browser Use Healthcheck
Expected workspace: <redacted-user-home>/Documents/Codex/2026-05-16/debug-and-resolve-why-browser-use

node_repl server processes: 2

No active Node REPL bridge/kernel processes found.

So the cross-chat stale bridge was cleared.

However, a clean node_repl probe in the reopened app still fails before any Browser-specific bootstrap:

nodeRepl.write(JSON.stringify({
  cwd: nodeRepl.cwd,
  homeDir: nodeRepl.homeDir,
  tmpDir: nodeRepl.tmpDir,
}, null, 2));

Actual:

node_repl kernel exited unexpectedly

node_repl diagnostics: {
  "kernel_pid": 55497,
  "kernel_status": "exited(code=1)",
  "kernel_stderr_tail": "Error: Operation not permitted (os error 1)",
  "reason": "stdout_eof",
  "stream_error": null
}

Controls:

/Applications/Codex.app/Contents/Resources/node -e "console.log(process.version); console.log(process.cwd())"

works:

v24.14.0
<redacted-user-home>/Documents/Codex/2026-05-16/debug-and-resolve-why-browser-use

The standalone node_repl server also works if launched with the built-in recovery flag:

/Applications/Codex.app/Contents/Resources/node_repl --disable-sandbox

Using a small JSON-RPC harness, that mode can initialize, list tools, and run the same JS successfully:

{
  "cwd": "<redacted-user-home>/Documents/Codex/2026-05-16/debug-and-resolve-why-browser-use",
  "homeDir": "<redacted-user-home>",
  "tmpDir": "<redacted-temp-dir>"
}

Additional local signal from the app-bundled sandbox command:

/Applications/Codex.app/Contents/Resources/codex sandbox macos --permissions-profile node_repl \
  -C <redacted-user-home>/Documents/Codex/2026-05-16/debug-and-resolve-why-browser-use \
  /Applications/Codex.app/Contents/Resources/node -e "console.log('profile-node-repl-test')"

returns:

WARNING: proceeding, even though we could not update PATH: Operation not permitted (os error 1)
Error: default_permissions requires a `[permissions]` table

The installed user config uses legacy sandbox settings, not the new permissions table:

approval_policy = "on-request"
sandbox_mode = "workspace-write"
approvals_reviewer = "guardian_subagent"
js_repl_node_path = "/Applications/Codex.app/Contents/Resources/node"

[plugins."browser@openai-bundled"]
enabled = true

[plugins."chrome@openai-bundled"]
enabled = true

Interpretation:

  1. There appear to be two distinct Browser Use failure modes:
  • Earlier: cross-chat/stale bridge workspace reuse.
  • Current after restart: fresh node_repl kernel cannot start under the default sandboxed path.
  1. The fresh failure is below Browser client setup. Browser plugin code never gets a chance to run.
  2. node_repl --disable-sandbox works, so the issue is specifically sandboxed kernel startup, not the bundled Node binary or JS runtime itself.
  3. The codex sandbox macos --permissions-profile node_repl repro suggests the runtime may be asking for a node_repl permissions profile that is not defined in legacy sandbox_mode configs, instead of resolving to a built-in or derived workspace profile.

Expected:

  • Browser's node_repl dependency should start under the normal sandbox on macOS when the app uses a valid legacy config (sandbox_mode = "workspace-write"), or it should internally map the node_repl runtime to a built-in permissions profile.
  • The runtime should not require users to globally weaken sandboxing with node_repl --disable-sandbox.
  • If a custom node_repl profile is required, the app should generate it, document it, or report a clear actionable error instead of surfacing only Operation not permitted.

Recommended fix direction:

  • In the node_repl launcher/runtime manager, avoid passing --permissions-profile node_repl unless that profile exists.
  • Prefer a built-in profile such as :workspace for the kernel, or derive the profile from the active thread permissions.
  • Add a regression test for a macOS/Desktop-style config that has sandbox_mode = "workspace-write" and no [permissions] table, asserting that node_repl can launch a kernel without --disable-sandbox.
  • Keep the prior IAB route/session ownership fixes as a separate layer; this report is specifically about failing before IAB discovery.
lgch3136 · 10 days ago

Adding a regression signature from the current macOS x64 build. The newer Desktop code now uses session routes rather than the older exact turn-route model, but the draft-to-persisted conversation transition still appears to break IAB ownership.

Environment

  • Codex Desktop: 26.707.31428 (build 5059)
  • Browser plugin: openai-bundled/browser/26.707.31428
  • macOS Intel / x86_64
  • In-app browser remains visible and manually usable
  • Screen Recording and Accessibility are granted
  • Native accessibility-based Computer Use can inspect, click, and scroll the same visible IAB page successfully

This is therefore not a general Intel, TCC permission, page-rendering, or website failure.

Sanitized lifecycle signature

The persisted conversation route is initially created and captured:

Conversation created conversationId=<persisted-id>
IAB_LIFECYCLE captured session route conversationId=<persisted-id>

Immediately afterward, the sidebar owner sync still reports its draft id even though the owner route already points at the persisted thread:

IAB_LIFECYCLE received browser sidebar owner sync
conversationId=client-new-thread:<temporary-id>
ownerRoutePath=/local/<persisted-id>

Desktop then reassigns the route in the opposite direction:

IAB_LIFECYCLE reassigned browser use route
sourceConversationId=<persisted-id>
targetConversationId=client-new-thread:<temporary-id>

The first getInfo can complete and create a host keyed by the temporary id, but immediately repeated requests for the persisted session fail:

IAB_LIFECYCLE created browser use host
conversationId=client-new-thread:<temporary-id>

IAB_LIFECYCLE iab backend info request completed
conversationId=<persisted-id>

IAB_LIFECYCLE iab backend info request failed
conversationId=<persisted-id>
errorMessage="No ChatGPT browser route is available for browser session <persisted-id>"

DOM snapshots, Runtime evaluation, screenshots through the IAB backend, and cursor actions then hang or reset the Node runtime even though tab metadata can still be read. The stack points into the packaged Desktop main process:

app.asar/.vite/build/main-BijF6dfW.js:681
ensureBrowserUseSessionRoute

Suggested fix/regression coverage

  • When a sidebar still reports client-new-thread:* but ownerRoutePath resolves to a persisted /local/<id>, canonicalize ownership to the persisted id.
  • Migrate the temporary route to the persisted route atomically; do not replace or dispose the active backend/session state during the rebind.
  • Keep any fallback scoped to the same window and canonical conversation.
  • Add a regression test for: draft thread opens IAB → thread becomes persisted → multiple concurrent/repeated getInfo calls → DOM snapshot → CDP evaluation → cursor/click.
  • Surface the precise alias/rebind rejection instead of collapsing it into a generic unavailable-route error.

This looks like the same general ownership/lifecycle failure class reported earlier in this issue, now reproduced after the session-route refactor.

maltsev-gorskij · 10 days ago

I’m seeing what appears to be the same general IAB session-binding problem, but I found a deterministic reproduction involving Codex collaboration subagents that I haven’t seen documented here yet. I hope these details help.

Environment

  • Codex Desktop: 26.707.31428 (build 5059)
  • Browser bundled plugin: 26.707.31428
  • macOS 26.2 (25C56)
  • Apple Silicon / arm64
  • Built-in Browser enabled
  • Browser approval: Always allow
  • Full CDP access enabled

Reproduction

  1. Start a normal root Codex thread.
  2. Initialize the bundled browser client through mcp__node_repl__js:

```js
const { setupBrowserRuntime } = await import(
"/Users/<user>/.codex/plugins/cache/openai-bundled/browser/26.707.31428/scripts/browser-client.mjs"
);

await setupBrowserRuntime({ globals: globalThis });
```

  1. In the root thread:

``js
await agent.browsers.list();
``

This succeeds and returns the Codex In-app Browser (type: "iab").

  1. Spawn any collaboration subagent and run the exact same browser bootstrap and discovery calls.
  1. In the subagent:

``js
await agent.browsers.list();
``

consistently returns:

``js
[]
``

and:

``js
await agent.browsers.get("iab");
``

fails with:

``text
Browser is not available: iab
``

  1. I reproduced this with multiple fresh child threads, including a child created from named .codex/agents profile and a separate unprofiled child. I also tested navigation to a public URL (https://www.google.com) to rule out localhost routing.
  1. Fully restarting Codex Desktop does not change the result.

Additional diagnostic finding

Both the root thread and subagent receive valid x-codex-turn-metadata, including session_id, thread_id, turn_id, and thread_source.

However, the current bundled browser-client.mjs derives the browser session binding differently for subagents:

root thread     -> use session_id
subagent thread -> use the child thread_id

IAB candidates are then filtered by comparing that derived value with the backend’s metadata.codexSessionId.

In my session:

IAB backend codexSessionId = root session_id
root lookup identifier     = root session_id       -> match
subagent lookup identifier = subagent thread_id    -> no match

This appears to deterministically produce the equivalent of a no-session-match result for every collaboration subagent, even though the same IAB backend is healthy and immediately available to the parent thread.

Expected behavior

Either:

  1. collaboration subagents should be allowed to attach to the parent thread’s IAB backend; or
  2. Codex Desktop should register a dedicated IAB backend/session binding for each child thread.

At the moment, Browser Use works in the root thread but appears structurally unavailable to all collaboration subagents.

This looks related to the turn/session ownership problems already discussed in this issue, but the deterministic subagent thread_id versus IAB root session_id mismatch may be a useful additional regression case.

Hamzablm · 8 days ago

I can reproduce this on a newer macOS Desktop build, even while the in-app browser is visibly open and manually usable.

Environment

  • Codex Desktop / ChatGPT app: 26.707.51957 (build 5175)
  • App-bundled CLI: codex-cli 0.144.0-alpha.4
  • Browser Use plugin: openai-bundled/browser-use/0.1.0-alpha1
  • macOS 26.5.2 (build 25F84)
  • Apple Silicon / arm64
  • Date reproduced: 2026-07-13

Reproduction

  1. Open the Codex in-app browser and navigate to an authenticated NotebookLM notebook.
  2. Explicitly ask the root thread to use @Browser to operate the existing tab.
  3. Confirm mcp__node_repl__js is available.
  4. Import the bundled scripts/browser-client.mjs and run:
const { setupAtlasRuntime } = await import("<browser-use plugin>/scripts/browser-client.mjs");
await setupAtlasRuntime({ globals: globalThis, backend: "iab" });
  1. Bootstrap fails before the selected tab can be acquired. Repeating the attempt while the same in-app tab remains visibly open produces the same result.

Exact failure

Failed to connect to browser-use backend "iab". No Codex IAB backends were discovered.
Discovery diagnostics: listedPipes=15, candidates=17, browsers=0, iabBrowsers=0,
failures=["discovered/connect/Error","discovered/connect/Error","discovered/connect/Error",
"discovered/connect/Error","discovered/connect/Error","discovered/connect/Error",
"discovered/connect/Error","discovered/connect/Error"], pipeListingError=none.

Expected

Browser Use should bind to the visible in-app browser for the active root thread and expose agent.browser.tabs.selected().

Actual / impact

The NotebookLM page remains visible and manually usable, but Browser Use sees zero browser/IAB backends. This blocked an authorized workflow to add study material and generate a NotebookLM Audio Overview.

This does not appear website-specific because the failure occurs during IAB bootstrap, before any page interaction.

S0L0RIEN · 5 days ago

Correction: this Windows-specific reproduction was mistakenly posted under the macOS-focused tracker. The complete report has been moved to #33332: https://github.com/openai/codex/issues/33332

Keeping this short redirect so existing references remain valid. Sorry for the noise.

jeremy9682 · 5 days ago

Additional current macOS evidence for the Browser/IAB route-binding and navigation-timeout class. This is separate from the launchd self-restart problem tracked in #32321.

Environment:

  • ChatGPT/Codex App 26.707.72221 build 5307
  • bundled codex-cli 0.144.2
  • bundled Browser plugin 26.707.72221
  • macOS 26.5.1 build 25F80, arm64

Observed split behavior:

  • Creating a blank tab, lightweight evaluation, and screenshot completed in roughly 44-73 ms after a clean restart.
  • goto() then hit the fixed outer timeout, including against a tiny test endpoint and a public control page.
  • Independent HTTP probes to the application endpoint averaged about 0.135 s, max 0.447 s, with no 5xx responses. This rules out the destination server as the source of the 30-60 second delay.
  • Desktop logs contained:
  • No ChatGPT browser route is available
  • Cannot find context with specified id
  • route window is not live
  • repeated unknown conversation events
  • During a multi-agent investigation, 682 unknown conversation events were observed in a ten-minute log window. Browser work issued from collaboration subagent conversations was markedly less reliable than root-thread-only browser work.

There was also stale ownership on the external Chrome backend: a kernel timeout could terminate the browser-client watcher before turnEnded/finalize released the tab lease. The extension persisted TAB_LEASES in session storage without an observed TTL/owner-liveness cleanup path. Restarting/reloading the Chrome extension cleared that lease, but it did not fix the IAB goto() timeout.

The practical mitigation was:

  • keep all navigation, claim, screenshot, and finalize operations in the root thread;
  • do not let collaboration subagents control Browser/IAB;
  • split navigation, lightweight state read, DOM read, and screenshot into separate calls;
  • stop after the first route-missing error instead of repeatedly retrying the same navigation.

Suggested areas to inspect:

  1. Route ownership when a persisted root conversation and client-new-thread:*/subagent conversations share the same Browser pane.
  2. Fail-fast behavior when no live route is available; a route error should not be allowed to consume the full navigation watchdog.
  3. Cleanup of Browser/Chrome tab leases when a Node REPL kernel is reset or killed.
  4. A supported rebind/recover operation that does not require restarting the entire desktop app.

Related active-pane/window binding report: #20743.

gallien · 4 days ago

Additional macOS reproduction with a currently active IAB socket but empty backend discovery.

Environment:

  • ChatGPT/Codex Desktop: 26.707.91948
  • App build: 5440
  • Bundle identifier: com.openai.codex
  • Codex CLI: 0.144.5
  • macOS: 26.5.2 (25F84)
  • Architecture: arm64
  • Browser plugin: openai-bundled/browser/26.707.91948

Observed result:

agent.browsers.list() => []
agent.browsers.get("iab") => Browser is not available: iab

The current ChatGPT process creates and actively holds a fresh Unix socket under /private/tmp/codex-browser-use/, but the browser runtime does not discover the backend. The Node runtime receives current session_id, thread_id, and turn_id metadata.

Verified:

  • browser_use, browser_use_external, and in_app_browser are enabled
  • Browser-client version matches the desktop app version
  • Browser-client SHA-256 matches the trusted hash in config.toml
  • codesign --verify --deep --strict succeeds
  • Gatekeeper reports accepted, source Notarized Developer ID
  • No stale openai-internal-testing or browser-use/0.1.0-alpha1 plugin exists

Recovery attempts:

  • Reinstalled the desktop app
  • Removed old ~/.codex/browser/sessions state
  • Removed stale /private/tmp/codex-browser-use sockets
  • Fully restarted the desktop app
  • Started a fresh thread and retried discovery

After restarting, the app created and held a fresh IAB socket, but no new browser session file was created and discovery still returned an empty list.

The recurring /private/var/db/DetachedSignatures system-log entry does not appear causal: signature, notarization, and Gatekeeper validation all succeed. No IAB crash, signature rejection, or sandbox denial is logged during the fresh startup.

This also resembles the empty-backend registration behavior reported in #26470.

gallien · 4 days ago

Follow-up with a more specific macOS A/B result after updating to Desktop 26.715.21316:

The current IAB socket exists and is actively held by the ChatGPT process. A direct Unix-socket connection from the Node REPL kernel fails before any getInfo or session/turn ownership check is reached:

Error: connect EPERM /private/tmp/codex-browser-use/<socket>.sock

Using the exact same app-bundled Node binary outside the Node REPL Seatbelt context connects successfully to the same live socket:

/Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node <connect-test> <same-socket>
connected

Current Node REPL turn metadata reports:

sandbox = seatbelt
thread_source = user
session_id == thread_id

This rules out the collaboration-subagent session_id versus child thread_id mismatch for this reproduction: it is a root/user thread and both identifiers are already identical. The connection is denied before the backend can return metadata.codexSessionId.

Additional observations:

  • agent.browsers.list() initially returned [].
  • Later, the Chrome extension backend registered and became visible while the runtime still reported sandbox: seatbelt.
  • The IAB backend remained unavailable.
  • This shows the general browser runtime and Chrome discovery can operate while the local IAB Unix-socket path remains inaccessible.

The bundled node_repl --help exposes --disable-sandbox, but Desktop rewrites [mcp_servers.node_repl].args to [] at startup, and the already managed Node REPL process continued to report sandbox: seatbelt. Therefore this was not usable as a controlled local workaround and was reverted.

Likely fix area: permit the managed Node REPL Seatbelt profile to connect to the app-owned /private/tmp/codex-browser-use/*.sock endpoints, or locate the IAB socket in an IPC path already granted to that profile.