Skip to content

Orphaned Chrome processes block session restart and cause authentication re-login loop #312

@atani

Description

@atani

Problem

When the daemon process dies unexpectedly (crash, forced kill, or certain session-stop timing issues), the Chrome browser process it spawned becomes orphaned but continues running. This creates a cascading failure:

  1. Orphaned Chrome holds the userDataDir locklaunchPersistentContext prevents reusing the same userDataDir while another Chrome instance is using it
  2. New session can't reuse previous cookies — starting a new session either errors out ("Browser is already in use for ...") or requires a fresh userDataDir
  3. Authentication state is lost — for SAML/SSO-protected sites, the session cookie (_fi_sess on GitHub Enterprise, for example) is a session cookie (expires=0), meaning it's destroyed when the Chrome process terminates
  4. Process accumulation — repeating this cycle accumulates orphaned Chrome processes (I had 47 at one point)

Root cause analysis

The daemon spawns Chrome with detached: true + child.unref() (program.js:201-214), which correctly decouples the daemon from its parent. However, when the daemon exits (via session-stopgracefullyProcessExitDoNotHang), the Chrome process it launched is not guaranteed to terminate:

  • Context.disposeAll() calls browserContext.close(), which should close Chrome
  • But if this takes longer than the 15-second watchdog timeout (watchdog.js:32), process.exit(0) is called while Chrome is still running
  • The orphaned Chrome process has no parent to send SIGTERM to it

Evidence

$ playwright-cli session-list
  (no sessions)

$ playwright-cli open https://example.com
Error: Browser is already in use for /Users/me/.playwright-cli/ghe-profile

$ ps aux | grep ghe-profile | head -1
user  93516  ...  /Applications/Google Chrome.app/.../Google Chrome --user-data-dir=/Users/me/.playwright-cli/ghe-profile --remote-debugging-port=55665 ...

$ ps -o ppid= -p 93516
  → Parent process gone (orphan!)

Proposed solution

1. Kill orphaned Chrome on session-stop (critical)

Before or after sending the "stop" message to the daemon, detect and kill Chrome processes associated with the session's userDataDir. This could use:

  • The CDP port recorded during launch to send Browser.close() via CDP
  • Or lsof / process scanning to find Chrome processes using the specific userDataDir

2. Reconnect to orphaned Chrome via CDP (nice-to-have)

If a Chrome process is found with a known --remote-debugging-port, attempt CDP reconnection instead of launching a new instance. This would preserve the existing authentication state.

3. Cookie persistence across session restarts (nice-to-have)

Add cookies export <file> / cookies import <file> commands (similar to browser-use CLI) to save/restore authentication state. This would help with SAML/SSO sites where session cookies are lost on browser restart.

Environment

  • OS: macOS (Darwin 25.3.0)
  • playwright-cli: 0.0.61 (@playwright/cli)
  • Browser: Google Chrome (system Chrome via --profile)

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions