Playwright Chromium fails in Codex Desktop macOS sandbox with MachPortRendezvousServer permission denied
What version of Codex is running?
- Codex CLI:
0.116.0 - Codex Desktop app: unknown from the agent session
What platform is your computer?
- macOS
26.4.1(25E253) - Apple Silicon / arm64
- Node.js
v25.8.1 - Playwright
1.59.1
What issue are you seeing?
When Codex Desktop runs a local Playwright Chromium launch inside the default sandboxed command/runtime path, Chromium crashes during startup with a macOS Mach bootstrap permission error:
FATAL:base/apple/mach_port_rendezvous_mac.cc:159
Check failed: kr == KERN_SUCCESS.
bootstrap_check_in org.chromium.Chromium.MachPortRendezvousServer.<pid>: Permission denied (1100)
This prevents browser QA / screenshot smoke tests from running through sandboxed shell commands and through a Node REPL MCP/tool runtime. The same Playwright script works when run through Codex with escalated permissions.
Steps to reproduce
From a Codex Desktop session on macOS, in a local project that has Playwright installed:
node -e '(async()=>{const {chromium}=require("playwright");const browser=await chromium.launch({headless:true});const page=await browser.newPage();await page.goto("data:text/html,<title>ok</title>");console.log(await page.title());await browser.close();})().catch(e=>{console.error(String(e.message||e).split("\n").slice(0,10).join("\n"));process.exit(1);});'
Observed in the normal sandboxed command path: Chromium launches, then immediately exits/crashes with the MachPortRendezvousServer Permission denied (1100) error above.
Also reproduced via a Node REPL MCP/tool runtime using:
const { chromium } = await import('playwright');
const browser = await chromium.launch({ headless: true });
What did you expect to happen?
Codex should either:
- allow Chromium/Playwright to start successfully in an approved browser/test context, or
- detect this macOS sandbox failure and prompt for escalation with a clear message, or
- route browser automation through a Codex-supported browser tool path.
What happened instead?
Chromium fails inside the sandbox with:
[err] FATAL:base/apple/mach_port_rendezvous_mac.cc:159
bootstrap_check_in org.chromium.Chromium.MachPortRendezvousServer.<pid>: Permission denied (1100)
In some full Chrome for Testing launch variants, Playwright reports the browser closed and then has trouble killing the process from inside the sandbox:
exception while trying to kill process: Error: kill EPERM
Additional testing
These variants were tried and did not resolve the sandboxed failure:
- default Playwright Chromium headless shell
- full
chromium.executablePath()/ Chrome for Testing channel: 'chromium'args: ['--disable-features=MachPortRendezvous']args: ['--disable-features=DialMediaRouteProvider,MediaRouter']
The same kind of Playwright launch succeeds when Codex runs the command with escalated permissions outside the sandbox.
Workaround
Use an escalated shell command for Playwright browser QA, or avoid launching Chromium from sandboxed tool runtimes such as the Node REPL MCP. A more durable workaround is to create a scoped script like npm run browser:smoke and approve that command prefix.
Why this matters
Browser-game/frontend verification flows in Codex Desktop often need Playwright for screenshots, console checks, and canvas/WebGL smoke tests. On macOS, the default sandbox currently makes that workflow fail in a way that looks like a Chromium/Playwright crash rather than an actionable Codex permission boundary.
4 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Root Cause
Chromium's multi-process architecture relies on registering a global Mach port for IPC between the main process and its child processes (renderer, GPU, utility). At startup, the main process calls
bootstrap_check_in()to register:This is a global Mach port name, not a local one. The current Seatbelt base policy (
seatbelt_base_policy.sbpl) only allows local Mach port registration — it does not include any(allow mach-register ...)rule for global names matchingorg.chromium.*.When this registration is denied by the kernel sandbox, Chromium hits
KERN_FAILUREand crashes with:No Chromium flag (
--no-sandbox,--disable-features=MachPortRendezvous, etc.) can work around this — it's an OS-level denial that happens before Chromium's own sandbox initialization.Fix
Add a single rule to
codex-rs/sandboxing/src/seatbelt_base_policy.sbpl:This precisely scopes the allow to Chromium's namespace without opening up arbitrary global Mach port registration. The regex anchors to
^org\.chromium\.so only Chromium-family processes benefit.Additionally, these supplementary rules reduce non-fatal but noisy denies from headless Chromium:
Context
Headless Chromium (via Playwright/Puppeteer) is a common workflow for AI coding agents — screenshot verification, frontend smoke tests, browser-visible behavior checks. This is the same pattern used by Claude Code's
/verifyand browser review workflows, and by Codex's own Computer Use feature.I maintain a Seatbelt sandbox wrapper for Claude Code that reuses Codex's base
.sbplpolicies. Adding themach-registerrule above resolved the issue completely — Playwright headless runs inside the sandbox without any escalation prompt.Happy to open a PR if this direction looks right.
Thanks @wlccgp3 for the solution.
I ran to the exact same issue.
I'm using Playwright version 1.61.1
I also had to add this rule for it to work
(allow mach-lookup (global-name-regex #"^org\.chromium\."))Reproduced this exact failure on 2026-08-22 from Codex Desktop on Apple Silicon/macOS while profiling a Rails 8.1/Minitest suite whose system tests use Capybara + Playwright-managed Chromium.
The sandboxed full-suite command reached the browser population and repeatedly produced:
Playwright was launching its worktree-managed
chromium-1234full build in headless mode (the executable bundle is namedGoogle Chrome for Testing.app). Because the suite retries browser failures, the sandbox denial caused repeated launch/abort attempts and visible macOS crash dialogs. The run ended with 15 environmental browser errors, while the equivalent browser population passes on the same project's Apple CI runner outside the Codex seatbelt.The additional impact for repository test runners is that a normal full-suite command can execute all non-browser tests but return invalid/partial browser evidence that looks like an application regression. Early detection plus an actionable narrow-escalation prompt—or routing a repository-owned browser runner through a scoped approval—would prevent both the misleading result and repeated crash dialogs. Broad sandbox disabling is not an acceptable workaround for this workflow.