Node REPL sandbox blocks Chromium/Playwright launch — MachPortRendezvousServer bootstrap_check_in denied (1100)

Open 💬 0 comments Opened Jul 8, 2026 by kjdaby87

Summary

Chromium (via the bundled Playwright) cannot launch from the Codex Node REPL. The browser process aborts at Mach service check-in with Permission denied (1100) (BOOTSTRAP_NOT_PRIVILEGED). The same bundled Playwright binary launches successfully from a normal elevated shell, so this is specific to the sandbox/seatbelt profile applied to the REPL child process, not to Playwright or the browser cache.

Environment

  • Codex.app: 26.623.141536 (build 4753)
  • Bundled Node: v24.14.0
  • Bundled Playwright: 1.57.0 (/Applications/Codex.app/Contents/Resources/cua_node/lib/node_modules/playwright)
  • Chromium headless-shell revision: 1200 (and 1228)
  • macOS: 26.5.2 (25F84), Apple Silicon (arm64)

Steps to reproduce

In the Codex Node REPL:

const pw = await import('playwright');
const browser = await pw.chromium.launch({ headless: true });
await browser.close();

Actual result

browserType.launch: Target page, context or browser has been closed
FATAL:base/apple/mach_port_rendezvous_mac.cc:156
Check failed: kr == KERN_SUCCESS.
bootstrap_check_in org.chromium.Chromium.MachPortRendezvousServer.<pid>: Permission denied (1100)

Also logged before the SIGTRAP:

ThermalStateObserverMac unable to register to power notifications
DNS config watch failed to start / Failed to read DnsConfig

Directly launching the chromium_headless_shell binary from the REPL fails identically.

Expected result

browser.close() returns cleanly, as it does from a normal shell.

Confirmation it is the sandbox, not Playwright/cache

The identical binary works outside the REPL. Smoke script run from an elevated shell:

// /private/tmp/gchrenov_playwright_smoke.mjs
import { chromium } from '/Applications/Codex.app/Contents/Resources/cua_node/lib/node_modules/playwright/index.mjs';
const browser = await chromium.launch({ headless: true });
await browser.close();
console.log('playwright launch ok');
$ node /private/tmp/gchrenov_playwright_smoke.mjs
playwright launch ok

Runnable scripts (smoke test + the verify and compare-probe QA scripts): https://gist.github.com/kjdaby87/5293147f3b070f1b0e3fc1f2f48d848f

Root cause (analysis)

Error 1100 = BOOTSTRAP_NOT_PRIVILEGED. Chromium's multi-process model requires the browser process to register a Mach service (bootstrap_check_in for MachPortRendezvousServer) so child processes (renderer/GPU/zygote) can rendezvous. The REPL's macOS seatbelt sandbox does not permit mach-register for the org.chromium.Chromium.MachPortRendezvousServer.* global name, so check-in fails and the process traps. This fires on every launch, including --headless; no Chromium launch flag bypasses it (--no-sandbox / --single-process do not help — the rendezvous server is constructed regardless).

Suggested fix

Add a mach-register allowance for the Chromium rendezvous global-name prefix to the Node REPL's sandbox profile, e.g.:

(allow mach-register (global-name-prefix "org.chromium.Chromium.MachPortRendezvousServer"))

(Chromium/Electron ship an analogous allowance in their own seatbelt profiles.) If browser automation from the REPL isn't intended to be supported, documenting that — and pointing users to run Playwright from a shell — would also resolve the confusion.

Impact / workaround

Browser automation (Playwright QA) from the Node REPL is unusable. Workaround: run Playwright from an elevated shell outside the REPL, which works reliably.

View original on GitHub ↗