From 281494ae52578f856e4942f621ea941d6b2e39af Mon Sep 17 00:00:00 2001 From: Veast <961171432@qq.com> Date: Mon, 2 Mar 2026 15:08:52 +0800 Subject: [PATCH] fix(browser): include Chrome stderr and sandbox hint in CDP startup error (#29355) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(browser): include Chrome stderr and sandbox hint in CDP startup error (#29312) When Chrome fails to start and CDP times out, the error message previously contained no diagnostic information, making it impossible to determine why Chrome couldn't start (e.g. missing --no-sandbox in containers, GPU issues, shared memory errors). This change: - Collects Chrome's stderr output and includes up to 2000 chars in the error - On Linux, if noSandbox is not set, appends a hint to try browser.noSandbox: true Closes #29312 * chore(browser): format chrome startup diagnostics * fix(browser): detach stderr listener after Chrome starts to prevent memory leak Named the anonymous listener so it can be removed via proc.stderr.off() once CDP is confirmed reachable. Also clears the stderrChunks array on success so the buffered data is eligible for GC. Fixes the unbounded memory growth reported in code review: a long-lived Chrome process emitting periodic warnings would keep appending to stderrChunks indefinitely since the listener was never removed. Addresses review comment from chatgpt-codex-connector on PR #29355. * changelog: note cdp startup diagnostics improvement --------- Co-authored-by: Vincent Koc Co-authored-by: 派尼尔 --- CHANGELOG.md | 1 + src/browser/chrome.ts | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cebf72c5021..5992a979a60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ Docs: https://docs.openclaw.ai - Browser/Extension navigation reattach: preserve debugger re-attachment when relay is temporarily disconnected by deferring relay attach events until reconnect/re-announce, reducing post-navigation tab loss. (#28725) Thanks @stone-jin. - Browser/Profile defaults: prefer `openclaw` profile over `chrome` in headless/no-sandbox environments unless an explicit `defaultProfile` is configured. (#14944) Thanks @BenediktSchackenberg. - Browser/Remote CDP ownership checks: skip local-process ownership errors for non-loopback remote CDP profiles when HTTP is reachable but the websocket handshake fails, and surface the remote websocket attach/retry path instead. (#15582) Landed from contributor (#28780) Thanks @stubbi, @bsormagec, @unblockedgamesstudio and @vincentkoc. +- Browser/CDP startup diagnostics: include Chrome stderr output and a Linux no-sandbox hint in startup timeout errors so failed launches are easier to diagnose. (#29312) Thanks @veast. - Docker/Image health checks: add Dockerfile `HEALTHCHECK` that probes gateway `GET /healthz` so container runtimes can mark unhealthy instances without requiring auth credentials in the probe command. (#11478) Thanks @U-C4N and @vincentkoc. - Docker/Sandbox bootstrap hardening: make `OPENCLAW_SANDBOX` opt-in parsing explicit (`1|true|yes|on`), support custom Docker socket paths via `OPENCLAW_DOCKER_SOCKET`, defer docker.sock exposure until sandbox prerequisites pass, and reset/roll back persisted sandbox mode to `off` when setup is skipped or partially fails to avoid stale broken sandbox state. (#29974) Thanks @jamtujest and @vincentkoc. - Daemon/systemd checks in containers: treat missing `systemctl` invocations (including `spawn systemctl ENOENT`/`EACCES`) as unavailable service state during `is-enabled` checks, preventing container flows from failing with `Gateway service check failed` before install/status handling can continue. (#26089) Thanks @sahilsatralkar and @vincentkoc. diff --git a/src/browser/chrome.ts b/src/browser/chrome.ts index 9501d1e4d98..d6dc9990ffd 100644 --- a/src/browser/chrome.ts +++ b/src/browser/chrome.ts @@ -285,6 +285,16 @@ export async function launchOpenClawChrome( } const proc = spawnOnce(); + + // Collect stderr for diagnostics in case Chrome fails to start. + // The listener is removed on success to avoid unbounded memory growth + // from a long-lived Chrome process that emits periodic warnings. + const stderrChunks: Buffer[] = []; + const onStderr = (chunk: Buffer) => { + stderrChunks.push(chunk); + }; + proc.stderr?.on("data", onStderr); + // Wait for CDP to come up. const readyDeadline = Date.now() + 15_000; while (Date.now() < readyDeadline) { @@ -295,16 +305,26 @@ export async function launchOpenClawChrome( } if (!(await isChromeReachable(profile.cdpUrl, 500))) { + const stderrOutput = Buffer.concat(stderrChunks).toString("utf8").trim(); + const stderrHint = stderrOutput ? `\nChrome stderr:\n${stderrOutput.slice(0, 2000)}` : ""; + const sandboxHint = + process.platform === "linux" && !resolved.noSandbox + ? "\nHint: If running in a container or as root, try setting browser.noSandbox: true in config." + : ""; try { proc.kill("SIGKILL"); } catch { // ignore } throw new Error( - `Failed to start Chrome CDP on port ${profile.cdpPort} for profile "${profile.name}".`, + `Failed to start Chrome CDP on port ${profile.cdpPort} for profile "${profile.name}".${sandboxHint}${stderrHint}`, ); } + // Chrome started successfully — detach the stderr listener and release the buffer. + proc.stderr?.off("data", onStderr); + stderrChunks.length = 0; + const pid = proc.pid ?? -1; log.info( `🦞 openclaw browser started (${exe.kind}) profile "${profile.name}" on 127.0.0.1:${profile.cdpPort} (pid ${pid})`,