Skip to content
5 changes: 5 additions & 0 deletions .changeset/wakeful-pogona-of-stamina.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"stagehand": patch
---

simple event loop timeout for strict event loops for async playwright (which has blocking start)
5 changes: 4 additions & 1 deletion stagehand/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,10 @@ async def init(self):
self.logger.debug("Initializing Stagehand...")
self.logger.debug(f"Environment: {self.env}")

self._playwright = await async_playwright().start()
# Initialize Playwright with timeout
self._playwright = await asyncio.wait_for(
async_playwright().start(), timeout=30.0 # 30 second timeout
)

if self.env == "BROWSERBASE":
# Create session if we don't have one
Expand Down
25 changes: 25 additions & 0 deletions tests/unit/test_client_initialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,31 @@ def test_init_as_context_manager(self):
# Verify close is called in __aexit__
assert client.close is not None

@pytest.mark.asyncio
async def test_init_playwright_timeout(self):
"""Test that init() raises TimeoutError when playwright takes too long to start."""
config = StagehandConfig(env="LOCAL")
client = Stagehand(config=config)

# Mock async_playwright to simulate a hanging start() method
mock_playwright_instance = mock.AsyncMock()
mock_start = mock.AsyncMock()

# Make start() hang indefinitely
async def hanging_start():
await asyncio.sleep(100) # Sleep longer than the 30s timeout

mock_start.side_effect = hanging_start
mock_playwright_instance.start = mock_start

with mock.patch("stagehand.main.async_playwright", return_value=mock_playwright_instance):
# The init() method should raise TimeoutError due to the 30-second timeout
with pytest.raises(asyncio.TimeoutError):
await client.init()

# Ensure the client is not marked as initialized
assert client._initialized is False

@pytest.mark.asyncio
async def test_create_session(self):
"""Test session creation."""
Expand Down