fix(next): do not start Chromium under an open-file limit it would run out of
Summary
Under a hard RLIMIT_NOFILE below 1024 (a launch from a shell after ulimit -n 256, which sets both limits), the app cannot raise its open-file limit, and Chromium aborted the whole app about 6 s after launch. Its child launch treats a failed pipe() as fatal: sandbox/mac/seatbelt_exec.cc:86-87, PFatal("SeatbeltExecClient: pipe failed"), EMFILE.
Found by the restore/chaos fuzz (fuzz catalog row h, finding h1): run h2-fd seed 2012, cmux21, pid 23845, 2026-10-31 10:15:04Z, feat d1f0e63691a0 Debug. Symbolicated with the fork's unstripped engine cef-154.0.28-cmux.28-macos-arm64-debug.tar.xz (the engine UUID matches the crash report). The crashing thread: ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread -> sandbox::SeatbeltExecClient::SeatbeltExecClient() -> sandbox::logging::PFatal -> abort_report_np. The app's stderr shows FILE_ERROR_TOO_MANY_OPENED in the same second. This is not memory pressure: the hog had ended 47 s earlier, and with the 15 GB hog the same build relaunched 82 times with 0 deaths.
Change
CEFRuntime.loadLibraryrefuses to start Chromium, before the framework is mapped, when the soft limit after the app's own raise is belowOpenFileLimit.chromiumFloor(1024). So no Chromium thread runs.- The failure is typed (
CEFUnavailableReason.openFileLimit). Chromium tabs wait in place (WebKit would open them signed out) with a localized notice that names the limit and the way out (start from Finder or the Dock, or raiseulimit -n). An explicit Chromium request gets the same text. - Agent chats in Chromium (
agent.chromium):ChromiumPageHost.isAvailablenow reads the refused start, so new chats open in WebKit. A chat that asked before the refusal reopens in WebKit at once. - It is logged once, and the start is not tried again. No retry, no relaunch loop, no catch of the abort. Terminals, the daemon and WebKit pages do not change.
- A launch from Finder, the Dock or
openalways raises to at least 10240, so only a lowered hard limit is refused. - The floor value is a judgement for now. A measurement on a mini (hard limits 512, 1024, 2048 with the restored session and 5 Chromium tabs) is queued; the value and its numbers go into the code comment when it is done.
Tests (red first)
- Red
3f4f7507fa3:OpenFileLimitTests(aHardLimitOf256KeepsChromiumFromStartingand 3 more),CEFOpenFileFloorTests.aHardLimitOf256RefusesTheLoad. - At the head also:
CEFOpenFileFloorTests.theRefusalNamesTheLimitAndKeepsTabsOutOfWebKit,aRefusedStartIsUnavailableWithItsReason,PageWebViewChromiumTests.anAgentChatInChromiumFallsBackToWebKitWhenChromiumIsRefused.
Observed / Not run
- Observed: fleet compile-check
e41127457b18b29d053c48f0at632d52ad8e2: CmuxNext, app and cmux-tui ok.prepush-gate.py: no new violations,app_lines+0.localization_catalog.py check: no finding for the new key (21 locales). - Not run: the red and green Mac test runs.
proof-step.pyrefuses Mac steps for this branch until it is on the Mac lane allow list (faster-2.md item 4); I asked the lead. - Not run: a real launch under
ulimit -n 256with the fix (part of the queued floor measurement).
No capture: the notice shows only under a hard open-file limit below 1024; a real capture comes with the floor measurement.
Changelog
Fixed: cmux no longer quits when it starts with a very low open-file limit; web pages show a notice that names the limit instead.
perf claim: none
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes the app aborting about 6 seconds after launch when started under a hard open-file limit below 1024 — Chromium treated a failed pipe() on its child-launch path as fatal. The app now refuses to start Chromium before its framework is loaded when the limit is too low, and shows a notice instead of crashing.
- Refusal is typed (
openFileLimit): Chromium tabs wait in place with a localized notice that names the limit and the way out, instead of opening signed out in WebKit. - Agent chats in Chromium open in WebKit when Chromium is refused; a chat already asking reopens in WebKit at once.
- A refused start is logged once and never retried.
- The 1024 floor is backed by a cmux21 measurement: the app process peaked at about 270 open descriptors, and hard limits of 512, 1024, and 2048 produced no aborts.