[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 2 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 ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗