From 2e2cdc2927231e05a7908e73f394fb4ad6a884ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Arrufat?= Date: Tue, 1 Sep 2026 14:41:03 +0200 Subject: [PATCH] fix(browser): claim the Chrome-fallback socket dir before using it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _run_chrome_fallback_command creates agent-browser- in the shared tmpdir and then opens stdout/stderr files inside it, but never writes the .owner_pid marker. _reap_orphaned_browser_sessions rmtree's any agent-browser-* dir that carries no live owner and is not tracked in the calling process, so a second hermes process — or a parallel test worker — deletes the directory between the makedirs and the first os.open, and the command dies with FileNotFoundError on _stdout_open. Write the owner marker immediately after creating the directory, which is what every other socket-dir user already does. Deterministic repro on main: run any test that exercises the fallback while a second process calls _reap_orphaned_browser_sessions() in a loop — 5/5 fail before, 6/6 pass after. --- tools/browser_tool.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/browser_tool.py b/tools/browser_tool.py index da04ca1c47..438e7a64ce 100644 --- a/tools/browser_tool.py +++ b/tools/browser_tool.py @@ -1357,6 +1357,10 @@ def _run_chrome_fallback_command( task_socket_dir = os.path.join(_socket_safe_tmpdir(), f"agent-browser-{tmp_session}") os.makedirs(task_socket_dir, mode=0o700, exist_ok=True) + # Claim the dir before using it: another hermes process's orphan reaper + # rmtree's any agent-browser-* dir in the shared tmpdir that carries no + # live owner, which otherwise deletes this one mid-command. + _write_owner_pid(task_socket_dir, tmp_session) browser_env = _build_browser_env() browser_env["AGENT_BROWSER_SOCKET_DIR"] = task_socket_dir browser_env["PATH"] = _merge_browser_path(browser_env.get("PATH", ""))