[BUG] macOS sandbox blocks Chromium/Playwright launch: bootstrap_check_in denied — no mach-register allowance exists, allowMachLookup cannot help

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 3 comments · opened Jul 30, 2026

Summary

Headless Chromium (Playwright, Puppeteer, anything Chromium-based) cannot launch inside the macOS Bash sandbox. Chromium's multi-process launch registers a per-pid Mach bootstrap service so its children can rendezvous with the parent; bootstrap_check_in is a mach-register operation, the Seatbelt profile is deny-by-default, and no setting can allow it: the profile contains no mach-register rule at all, and sandbox.network.allowMachLookup — whose schema docs mention Playwright — only ever emits (allow mach-lookup …) rules.

Error

[FATAL:base/apple/mach_port_rendezvous_mac.cc:159] Check failed: kr == KERN_SUCCESS. bootstrap_check_in org.chromium.Chromium.MachPortRendezvousServer.98874: Permission denied (1100)

The process is then force-killed and Playwright fails with TargetClosedError: BrowserType.launch: Target page, context or browser has been closed.

Root cause

sandbox-runtime's macOS profile (src/sandbox/macos-sandbox-utils.ts) allows a fixed list of mach-lookup names ("based on Chrome sandbox policy") plus user-specified allowMachLookup entries, but grepping the profile shows no mach-register allowance anywhere. Under (deny default), any process that must register a new bootstrap service name — Chromium's MachPortRendezvousServer.<pid>, crashpad's child_port_handshake — dies at launch. So allowMachLookup fixes the lookup class of failure (e.g. Go TLS needing trustd, #29533) but structurally cannot fix this one.

Reproduction

Inside a sandboxed Bash call on macOS, with Playwright + chromium installed:

python -c "from playwright.sync_api import sync_playwright; p = sync_playwright().start(); p.chromium.launch(headless=True)"

Workarounds (both fully unsandbox the command)

  • sandbox.excludedCommands matching the specific script
  • dangerouslyDisableSandbox: true per call (unavailable when allowUnsandboxedCommands: false)

Neither preserves filesystem/network isolation for the browser process, which is the part one actually wants sandboxed.

Suggested fix

A scoped registration allowance mirroring allowMachLookup, e.g.:

"sandbox": { "network": { "allowMachRegister": ["org.chromium.*"] } }

emitting (allow mach-register (global-name-prefix "org.chromium.")), so browser automation can run with the rest of the sandbox intact.

Prior reports

  • #14881 — identical failure (bootstrap_check_in … Permission denied (1100) from puppeteer/crashpad), auto-closed as stale with "please file a new issue and reference this one".
  • #29533 — the mach-lookup flavor of the same deny-default (Go TLS / trustd); addressed by enableWeakerNetworkIsolation/allowMachLookup, which cannot address registration.

Environment

  • macOS Darwin 25.5.0 (arm64)
  • Claude Code 2.1.220, sandbox enabled, allowUnsandboxedCommands: false
  • Playwright (Python) with chromium_headless_shell-1228

View original on GitHub ↗

3 Comments

samlaf · 2 months ago

Suggested tags: sandbox + macos

ir0nPotato · 1 month ago

Independent confirmation — same failure, different project/org

Hit this exact issue independently while running Angular's Vitest browser-mode unit tests (headless Chromium via @vitest/browser-playwright) inside the sandboxed Bash tool on macOS. Wanted to add a data point since this confirms the root cause is structural, not scope-dependent. Also tried allowMachLookup: [\"*\"] (full wildcard): identical failure, ruling out a scoping issue.

Environment

  • Claude Code 2.1.241
  • macOS 26.1 (build 25B78), arm64
  • vitest 4.1.10, @vitest/browser-playwright 4.1.10, playwright/playwright-core 1.56.1
  • Chromium chromium_headless_shell-1194
  • Sandbox: enabled: true, failIfUnavailable: true, allowUnsandboxedCommands: false

Error

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)

followed by Playwright's browserType.launch: Target page, context or browser has been closed, and a secondary kill EPERM when Playwright tries to force-kill the already-crashed process (also sandbox-denied, but a symptom, not a separate bug).

Workaround used

Same as noted here: sandbox.excludedCommands matching the test invocation runs the whole process tree (test runner → Playwright → Chromium) fully outside the sandbox. Confirmed working, but it fully drops filesystem/network isolation for that command, same caveat as already documented in this thread.

Adding this in case it helps: prioritizing a scoped allowMachRegister (mirroring allowMachLookup's design) would let CI/test tooling that spins up headless Chromium/Playwright run under sandbox without a full opt-out.

cschmookler · 19 days ago

Same failure here on Claude Code 2.1.282, macOS (Apple Silicon), Playwright's chrome-headless-shell:

bootstrap_check_in org.chromium.Chromium.MachPortRendezvousServer.<pid>: Permission denied (1100)

What we tried:

  • sandbox.network.allowMachLookup: ["org.chromium.*"]: settings load, same failure.
  • sandbox.allowMachLookup: true: loads, no effect.

A Seatbelt profile with (allow mach-register (global-name-regex #"^org\.chromium\.")) lets it start, which matches this issue's proposal. We'd use an allowMachRegister setting as soon as it exists; for now we run the browser outside the Claude Code sandbox, under its own profile.