browser-use/browser-use

LocalBrowserWatchdog deletes in-use temp user_data_dir after successful launch

Summary

  • Context: LocalBrowserWatchdog manages the local Chrome/Chromium browser subprocess lifecycle, including retry logic that creates temporary user_data_dir directories when the original directory is locked or in use.

  • Bug: When browser launch succeeds after a retry using a temporary directory, the code immediately deletes ALL temporary directories including the one actively being used by the running browser.

  • Actual vs. expected: The temporary user_data_dir is deleted while the browser process is still running and actively using it, instead of being preserved until browser cleanup. This corrupts the browser’s profile directory while it’s in use.

  • Impact: Browser crashes, data corruption, or undefined behavior when Chrome tries to write to the deleted user_data_dir during normal operation (cookies, cache, local storage, history, etc.).

Code with bug

# Success! Clean up any temp dirs we created but didn't use
for tmp_dir in self._temp_dirs_to_cleanup:
    # <-- BUG 🔴 This deletes ALL temp dirs, including the one in use!
    try:
        shutil.rmtree(tmp_dir, ignore_errors=True)
    except Exception:
        pass

return process, cdp_url

Example

  • First launch attempt fails due to a locked original user_data_dir (SingletonLock). A temp dir (e.g., /tmp/browseruse-tmp-abc123) is created, tracked in _temp_dirs_to_cleanup, and set as profile.user_data_dir.

  • Second attempt launches successfully using that temp dir.

  • Immediately after success, the cleanup loop deletes every temp dir in _temp_dirs_to_cleanup, including the currently used directory.

  • Result: the in-use temp directory is deleted while Chrome is running. Subsequent writes to cookies/cache/session can error, causing instability or corruption.

Evidence from a repro test confirms: a temp directory is created and used for the successful launch, and then exists()returns False immediately after launch, demonstrating it was deleted while in use.

Recommended fix

# Success! Clean up only the temp dirs we created but didn't use
currently_used_dir = str(profile.user_data_dir)

unused_temp_dirs = [
    tmp_dir
    for tmp_dir in self._temp_dirs_to_cleanup
    if str(tmp_dir) != currently_used_dir
]  # <-- FIX 🟢

for tmp_dir in unused_temp_dirs:
    try:
        shutil.rmtree(tmp_dir, ignore_errors=True)
    except Exception:
        pass

# Keep only the in-use directory for cleanup during browser kill
if currently_used_dir and "browseruse-tmp-" in currently_used_dir:
    self._temp_dirs_to_cleanup = [Path(currently_used_dir)]  # <-- FIX 🟢
else:
    self._temp_dirs_to_cleanup = []

return process, cdp_url