#22997: fix(browser): remove stale Chrome SingletonLock before launch
size: XS
Cluster:
Browser Enhancements and Fixes
## Summary
- Removes stale `SingletonLock`, `SingletonSocket`, and `SingletonCookie` files from the Chrome user-data directory before spawning Chrome in `launchOpenClawChrome()`
- Fixes Chrome refusing to start with **exit code 21** when the Docker container hostname changes across restarts
## Problem
When running OpenClaw in Docker with a persistent volume for `~/.openclaw/`, Chrome's Singleton files survive container restarts but encode the **old container's hostname**. On the next restart the container gets a new hostname, and Chrome sees:
```
ERROR:chrome/browser/process_singleton_posix.cc:363
The profile appears to be in use by another Chromium process (32)
on another computer (f408c5e12926). Chromium has locked the profile...
```
Chrome exits with code 21 and the browser tool silently times out with:
```
Can't reach the OpenClaw browser control service (timed out after 15000ms)
```
The existing `ensureProfileCleanExit()` handles the "didn't shut down correctly" recovery (`exit_type=Normal` in Preferences) but does not address the Singleton lock files.
## Root Cause
Chrome uses three symlink files in the user-data directory for profile locking:
- `SingletonLock` → `<hostname>-<pid>` (e.g., `f408c5e12926-32`)
- `SingletonSocket` → `/tmp/.../SingletonSocket`
- `SingletonCookie` → `<random>`
In Docker, the hostname changes on every `docker compose restart` or `docker compose down && up`. The persistent volume retains the old lock files, creating a hostname mismatch that Chrome treats as "profile in use by another computer."
## Fix
Added cleanup of all three Singleton files immediately before `spawnOnce()` in `launchOpenClawChrome()`. This is safe because:
1. Chrome recreates these files on every startup
2. If Chrome is actually running (not stale), the `ensurePortAvailable()` check earlier in the function would already fail
3. The cleanup only runs in the `launchOpenClawChrome` code path (local profiles), not for remote CDP or extension relay profiles
## Testing
Verified on a Hetzner VPS (Ubuntu 24.04, Docker 29.2.1, Chromium 145.0.7632.6):
1. Created stale Singleton files simulating a previous container hostname
2. Confirmed Chrome exit code 21 **without** the fix
3. Applied the fix → Chrome launches successfully on the expected CDP port
4. Full flow verified: Singleton cleanup → Chrome launch → Playwright `connectOverCDP` → page navigation → success
5. Tested across multiple container restarts — browser starts reliably every time
## Test plan
- [ ] Verify Chrome launches correctly on first browser tool call after gateway restart
- [ ] Verify no regression when Singleton files don't exist (fresh install)
- [ ] Verify no regression on non-Docker deployments (macOS app, Linux native)
- [ ] Verify `ensurePortAvailable` still catches genuinely running Chrome instances
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR adds cleanup of Chrome's Singleton lock files (`SingletonLock`, `SingletonSocket`, `SingletonCookie`) before launching Chrome in Docker environments. When Docker containers restart with new hostnames but persistent volumes, these files retain the old hostname and cause Chrome to exit with code 21, treating the profile as locked by another computer.
- Removes stale Singleton files immediately before the main Chrome spawn
- Addresses Docker-specific issue where hostname changes but user-data volume persists
- Safe cleanup: files are recreated by Chrome on startup, and `ensurePortAvailable` already guards against genuinely running instances
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge with minimal risk - it fixes a specific Docker issue without affecting other deployment scenarios
- The fix is well-targeted and addresses a real Docker containerization issue. The cleanup is safe (Chrome recreates these files) and protected by the earlier `ensurePortAvailable` check. Minor deduction for one edge case: if stale Singleton files exist during the bootstrap phase (when profile files don't exist yet), the bootstrap spawn could fail before reaching the cleanup. However, this scenario is unlikely in practice since Singleton files and profile files are typically created/removed together.
- No files require special attention
<sub>Last reviewed commit: 382bd52</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#13568: Fix browser (OpenClaw-managed) launch fail by binding remote debugg...
by singlag · 2026-02-10
78.0%
#8614: fix(browser): detect early chromium exit to prevent startup hang
by Wren-OC · 2026-02-04
77.5%
#19495: fix: handle Chrome process re-parenting on Windows
by andenwick · 2026-02-17
76.3%
#14944: fix(browser): prefer openclaw profile in headless/noSandbox environ...
by BenediktSchackenberg · 2026-02-12
74.7%
#9020: fix(browser): skip port ownership and WS reachability checks for re...
by yepack · 2026-02-04
73.3%
#19823: fix(browser): stability improvements for headless Chrome
by Milofax · 2026-02-18
73.2%
#22952: fix(browser): suggest remote profile when local Chrome is not insta...
by dashed · 2026-02-21
72.9%
#11553: feat(docker): add sandbox browser service and documentation
by dangphdh · 2026-02-08
72.9%
#22491: Use multi-stage docker build to reduce image size from 4.72GB -> 2....
by mm-zacharydavison · 2026-02-21
71.9%
#11333: fix(docker): align host directory ownership with container user
by liuxiaopai-ai · 2026-02-07
71.3%