From 68cf715266e2357842d0f549119b230fb8db4ec6 Mon Sep 17 00:00:00 2001 From: Derek Meegan Date: Thu, 26 Feb 2026 16:58:48 -0800 Subject: [PATCH 1/3] Wrap ensure_injection in try/catch to handle page navigation errors Co-Authored-By: Claude Opus 4.6 --- stagehand/page.py | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/stagehand/page.py b/stagehand/page.py index 3f2738e..bedf8f5 100644 --- a/stagehand/page.py +++ b/stagehand/page.py @@ -53,28 +53,33 @@ def update_root_frame_id(self, new_id: str): self._frame_id = new_id self._stagehand.logger.debug(f"Updated frame ID to {new_id}", category="page") - # TODO try catch here async def ensure_injection(self): """Ensure custom injection scripts are present on the page using domScripts.js.""" - exists_before = await self._page.evaluate( - "typeof window.getScrollableElementXpaths === 'function'" - ) - if not exists_before: - global _INJECTION_SCRIPT - if _INJECTION_SCRIPT is None: - import os + try: + exists_before = await self._page.evaluate( + "typeof window.getScrollableElementXpaths === 'function'" + ) + if not exists_before: + global _INJECTION_SCRIPT + if _INJECTION_SCRIPT is None: + import os - script_path = os.path.join(os.path.dirname(__file__), "domScripts.js") - try: - with open(script_path) as f: - _INJECTION_SCRIPT = f.read() - except Exception as e: - self._stagehand.logger.error(f"Error reading domScripts.js: {e}") - _INJECTION_SCRIPT = "/* fallback injection script */" - # Inject the script into the current page context - await self._page.evaluate(_INJECTION_SCRIPT) - # Ensure that the script is injected on future navigations - await self._page.add_init_script(_INJECTION_SCRIPT) + script_path = os.path.join(os.path.dirname(__file__), "domScripts.js") + try: + with open(script_path) as f: + _INJECTION_SCRIPT = f.read() + except Exception as e: + self._stagehand.logger.error(f"Error reading domScripts.js: {e}") + _INJECTION_SCRIPT = "/* fallback injection script */" + # Inject the script into the current page context + await self._page.evaluate(_INJECTION_SCRIPT) + # Ensure that the script is injected on future navigations + await self._page.add_init_script(_INJECTION_SCRIPT) + except Exception as e: + self._stagehand.logger.warning( + f"ensure_injection failed (page may be navigating): {e}", + category="page", + ) async def goto( self, From c918f29dd924c4f8ac77fe11580da08005a740f2 Mon Sep 17 00:00:00 2001 From: Derek Meegan Date: Thu, 26 Feb 2026 17:10:30 -0800 Subject: [PATCH 2/3] Scope ensure_injection catch to execution context destroyed errors Only swallow the "Execution context was destroyed" error from page navigation; re-raise all other exceptions. Co-Authored-By: Claude Opus 4.6 --- stagehand/page.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/stagehand/page.py b/stagehand/page.py index bedf8f5..352ad53 100644 --- a/stagehand/page.py +++ b/stagehand/page.py @@ -76,10 +76,13 @@ async def ensure_injection(self): # Ensure that the script is injected on future navigations await self._page.add_init_script(_INJECTION_SCRIPT) except Exception as e: - self._stagehand.logger.warning( - f"ensure_injection failed (page may be navigating): {e}", - category="page", - ) + if "Execution context was destroyed" in str(e): + self._stagehand.logger.warning( + f"ensure_injection failed (page may be navigating): {e}", + category="page", + ) + else: + raise async def goto( self, From cc41c3e6b4d37f60bed237ab39f2a344b25993fd Mon Sep 17 00:00:00 2001 From: Derek Meegan Date: Thu, 26 Feb 2026 17:15:23 -0800 Subject: [PATCH 3/3] Catch TargetClosedError instead of matching error string Co-Authored-By: Claude Opus 4.6 --- stagehand/page.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/stagehand/page.py b/stagehand/page.py index 352ad53..eb88148 100644 --- a/stagehand/page.py +++ b/stagehand/page.py @@ -2,6 +2,7 @@ import time from typing import Optional, Union +from playwright._impl._errors import TargetClosedError from playwright.async_api import CDPSession, Page from pydantic import BaseModel @@ -75,14 +76,11 @@ async def ensure_injection(self): await self._page.evaluate(_INJECTION_SCRIPT) # Ensure that the script is injected on future navigations await self._page.add_init_script(_INJECTION_SCRIPT) - except Exception as e: - if "Execution context was destroyed" in str(e): - self._stagehand.logger.warning( - f"ensure_injection failed (page may be navigating): {e}", - category="page", - ) - else: - raise + except TargetClosedError as e: + self._stagehand.logger.warning( + f"ensure_injection failed (page may be navigating): {e}", + category="page", + ) async def goto( self,