close
Skip to content

Browser Mode headless launch fails with ENOENT: generate_playwright_config() references a storage-state file the OSS build never creates #2209

Description

@Walsen

What

On a fresh install with Browser Mode enabled (headless --config path — i.e. any user not on the Chrome-extension path), every browser_* tool call fails at launch with:

Error reading storage state from <data-home>/playwright-storage-state.json:
ENOENT: no such file or directory, open '.../playwright-storage-state.json'

The browser binary launches, but Playwright cannot build a context because the config points contextOptions.storageState at a file that does not exist.

Environment: KiroCrew 0.1.2-insider (OSS build), @playwright/mcp (headless/config mode, not --extension), macOS (Chromium engine). Chromium binary present via npx @playwright/mcp install-browser chromium.

Steps to reproduce

  1. Fresh install, no Chrome extension paired (~/.kiro/crew/playwright-extension-mode absent → headless --config path).
  2. Enable Browser Mode (Settings → Browser). This writes playwright-config.json.
  3. Ensure the Chromium binary is installed (npx @playwright/mcp install-browser chromium).
  4. Trigger any browser_* tool (e.g. browser_navigate).

Expected: the browser launches with a clean context and navigation succeeds.
Actual: launch fails with ENOENT: ... playwright-storage-state.json. The file is never created anywhere on the machine.

Root cause (verified in the installed backend)

The config generator and the only writer of the storage-state file disagree, and the writer is a no-op in the OSS build:

  1. browser/setup.py:428 generate_playwright_config() unconditionally writes contextOptions.storageState (line 462) pointing at <config_dir>/playwright-storage-state.json:

    "contextOptions": {
        "storageState": storage_state,   # setup.py:462
    },
  2. browser/setup.py:472 refresh_storage_state() is the only function that writes that file — and in the OSS build it bails immediately (line 481) because the SSO cookie source is stubbed out:

    def refresh_storage_state() -> dict[str, Any]:
        cookie_path = _cookie_path()
        if not cookie_path.exists():
            return {"ok": False, "error": "browser auth not available in OSS"}
        ...

    (The module docstring confirms: "In the open-source build these steps are neutralized ... SSO setup is a no-op.")

  3. Playwright's storageState requires the file to exist; pointing it at a missing path throws ENOENT at context creation. Net effect: headless Browser Mode can never launch on a stock OSS install.

Note: playwright-storage-state.json is (correctly) on the sensitive-path allowlist in security.py, since it can hold session cookies — so this cannot be worked around by an agent seeding the file; it must be fixed in the generator.

Suggested fix

Only attach storageState when the file actually exists — a fresh OSS context needs no seeded auth:

storage_state = str(config_dir() / "playwright-storage-state.json")

context_options: dict[str, Any] = {}
# The OSS build's refresh_storage_state() is a no-op, so pointing Playwright at a
# non-existent storage-state file throws ENOENT at launch. Only attach it when present.
if Path(storage_state).exists():
    context_options["storageState"] = storage_state

config = {
    "browser": {
        "browserName": engine,
        "isolated": True,
        "launchOptions": launch_options,
        "contextOptions": context_options,
    },
    "capabilities": ["network", "storage"],
}

This self-heals: if a cookie source is ever wired and refresh_storage_state() writes the file, the next config regen picks it up automatically.

Why it matters

Every fresh OSS install using headless Browser Mode (the default for users not on the Chrome-extension path) has a non-functional browser out of the box, with an error that points at a file the product never creates. Distinct from #1634 (extension-token path, --extension) and #1273 (post-launch screencast height) — this is the headless --config launch path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: coreCore runtime utilities, config/paths, process singletonsbugSomething is not workingdocumentationDocumentation improvementsneeds-triageAwaiting automated triage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions