openclaw/openclaw · error · BrowserProfileUnavailableError

Chrome MCP existing-session attach failed for profile "${pro

Error message

Chrome MCP existing-session attach failed for profile "${profileName}". The Chrome MCP subprocess exited before it became usable.

What it means

Thrown as BrowserProfileUnavailableError (HTTP 409) by leaseSession when, after waitForChromeMcpReady reported the session ready, the transport PID was null on a second consecutive attempt (staleReadySessionRetries > 1). It means the Chrome MCP subprocess became ready and then immediately exited, twice in a row, so attaching is considered impossible for this profile right now.

Source

Thrown at extensions/browser/src/browser/chrome-mcp-session.ts:166

      leasedPending = createdPending;
      pendingLease = await waitForSharedPendingChromeMcpSession(createdPending, signal);
      session = pendingLease.session;
    }

    try {
      await waitForChromeMcpReady(session, profileName, timeoutMs, signal);
      if (session.transport.pid === null) {
        forgetCachedChromeMcpSessionIfCurrent(cacheKey, session);
        if (leasedPending) {
          forgetPendingChromeMcpSessionIfCurrent(cacheKey, leasedPending);
        }
        if (pendingLease) {
          await pendingLease.release(true);
          pendingLease = undefined;
        }
        staleReadySessionRetries += 1;
        if (staleReadySessionRetries > 1) {
          throw new BrowserProfileUnavailableError(
            `Chrome MCP existing-session attach failed for profile "${redactChromeMcpProfileLabelForDiagnostic(profileName)}". ` +
              "The Chrome MCP subprocess exited before it became usable.",
          );
        }
        continue;
      }
      return session;
    } catch (err) {
      if (signal?.aborted && pendingLease) {
        await pendingLease.release(true);
        pendingLease = undefined;
      } else if (pendingLease && leasedPending && leasedPending.state.waiters > 1) {
        await pendingLease.release(false);
        pendingLease = undefined;
      } else {
        forgetCachedChromeMcpSessionIfCurrent(cacheKey, session);
        if (leasedPending) {
          forgetPendingChromeMcpSessionIfCurrent(cacheKey, leasedPending);

View on GitHub (pinned to 01804a7531)

Solutions

  1. Run the Chrome MCP binary manually with the same flags and inspect stderr for the crash cause (missing lib, sandbox denial, lock error).
  2. Ensure no other Chrome instance is using the same user-data-dir; remove a stale SingletonLock if a previous Chrome crashed.
  3. On locked-down containers, configure the sandbox appropriately (or the documented container setup) rather than retrying blindly.
  4. Check that Chrome/Chromium is installed at a supported version and that the profile's executablePath points to it.

Example fix

# before: profile launches a crashing Chrome
# (configured executablePath points at incompatible chrome)

# after: reproduce the crash manually to see the real error
CHROME_LOG=$(mktemp)
"$CHROME_BIN" --remote-debugging-port=9222 \
  --user-data-dir="$PROFILE_DIR" about:blank 2>"$CHROME_LOG"
cat "$CHROME_LOG"   # inspect missing lib / sandbox / lock error
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: confirm Chrome binary runs and the user-data-dir is not locked
import { execFileSync } from "node:child_process";
try {
  execFileSync(chromePath, ["--version"], { stdio: "pipe", timeout: 2_000 });
} catch {
  // Chrome missing/unrunnable; fix before attempting to attach
}
if (existsSync(path.join(profileDir, "SingletonLock"))) {
  // stale lock from a crashed Chrome; remove only if no Chrome is running
}

Type guard

import { BrowserProfileUnavailableError } from "./errors.js";

function isAttachFailedError(err: unknown): err is BrowserProfileUnavailableError {
  return err instanceof BrowserProfileUnavailableError && /exited before it became usable/.test(err.message);
}

Try / catch

try {
  return await leaseSession(profileName, opts, timeoutMs, signal);
} catch (err) {
  if (err instanceof BrowserProfileUnavailableError && /exited before it became usable/.test(err.message)) {
    // reproduce the Chrome crash manually (see exampleFix) before retrying
    throw new Error("Chrome MCP crashes on startup; run the binary manually to inspect.");
  }
  throw err;
}

Prevention

When it happens

Trigger: Chrome MCP subprocess starts, signals ready, then crashes before its PID can be relied upon; on retry the same thing happens. Causes include bad launch flags, missing shared libraries, sandbox/seccomp killing the process, an incompatible Chrome/Chromium version, or a user-data-dir lock held by another Chrome instance.

Common situations: Chrome not installed or wrong version; user-data-dir already locked by a running Chrome with the same profile; missing libs in a minimal container; sandbox requiring --no-sandbox in the environment but not configured; incompatible Chrome MCP binary for the host architecture.

Related errors


AI-assisted analysis of openclaw/openclaw@01804a7531 (2026-08-12). Data as JSON: /api/errors/7afb0ff4997f5ea7. Report an issue: GitHub.