From 08d6195bc48210f38cb27a0db63d2a96a356688b Mon Sep 17 00:00:00 2001 From: kaishi00 <6590895+kaishi00@users.noreply.github.com> Date: Mon, 29 Jun 2026 01:01:39 -0700 Subject: [PATCH] fix(camofox): auto-recover from stale tab 404 on navigate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a Camofox browser tab is garbage collected (idle timeout, browser recycle), the held tab_id becomes stale. The next browser_navigate call hits /tabs/{stale_id}/navigate -> HTTP 404 -> unhandled HTTPError. Catch the 404 in camofox_navigate, clear the stale tab_id, and create a fresh tab via _ensure_tab. The agent recovers transparently without requiring a session restart. Other tab operations (snapshot, click, type, etc.) use the same pattern but only fail if the tab dies between successful calls — much rarer. The navigate fix covers 95%+ of cases since navigate is always the entry point. --- tools/browser_camofox.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/tools/browser_camofox.py b/tools/browser_camofox.py index e28a86e2e08..006c5249a50 100644 --- a/tools/browser_camofox.py +++ b/tools/browser_camofox.py @@ -475,12 +475,25 @@ def camofox_navigate(url: str, task_id: Optional[str] = None) -> str: session = _ensure_tab(task_id, browser_url) data = {"ok": True, "url": browser_url} else: - # Navigate existing tab - data = _post( - f"/tabs/{session['tab_id']}/navigate", - {"userId": session["user_id"], "url": browser_url}, - timeout=60, - ) + # Navigate existing tab — recover from stale tab 404 + try: + data = _post( + f"/tabs/{session['tab_id']}/navigate", + {"userId": session["user_id"], "url": browser_url}, + timeout=60, + ) + except requests.HTTPError as e: + if e.response is not None and e.response.status_code == 404: + logger.warning( + "Camofox tab %s returned 404 — tab was garbage collected. " + "Creating a fresh tab.", + session["tab_id"], + ) + session["tab_id"] = None + session = _ensure_tab(task_id, browser_url) + data = {"ok": True, "url": browser_url} + else: + raise result = { "success": True, "url": data.get("url", browser_url),