Skip to content

[Bug]: Task cancellation raises asyncio.InvalidState due to a cancelled future being set #2581

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
blubber opened this issue Oct 3, 2024 · 0 comments · Fixed by #2593
Closed
Assignees
Labels

Comments

@blubber
Copy link

blubber commented Oct 3, 2024

Version

1.47.0

Steps to reproduce

  1. Use the async_playwright context manager to open a context.
  2. Launch a new browser (only tested with Chromium).
  3. Create a new page.
  4. Within the async_playwright context create a task group, add at least two tasks, one should be a playwright task (i.e. page.<some_locator>.inner_text()).
  5. Add a second task that raises an exception.
  6. The exception will result in the task group being cancelled, which is not gracefully handled by playwright.

Expected behavior

I expected the task group to cancel the playwright task and than rereaise the original exception. This does happen, however, in cleaning up after cancellation playwright attempts to call set_exception on a future that is already cancelled.ror.

The problem appears to be in the cleanup method where set_exception is called on an already cancelled future. I verified this by putting a bunch of print statements in that particular code, and print(callback.fugure) printed <Future cancelled>. Calling set or set_exception an an already cancelled exception causes asyncio to raise a InvalidState error.

Actual behavior

Traceback (most recent call last):
  File "/Users/tiemo/Workspace/playwright_bug/test.py", line 21, in <module>
    asyncio.run(use_playwright())
  File "/opt/homebrew/Cellar/[email protected]/3.12.5/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/runners.py", line 194, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.12.5/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.12.5/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/base_events.py", line 687, in run_until_complet
e
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/Users/tiemo/Workspace/playwright_bug/test.py", line 11, in use_playwright
    async with async_playwright() as sp:
  File "/Users/tiemo/Workspace/playwright_bug/venv12/lib/python3.12/site-packages/playwright/async_api/_context_manager.py", line 57, in __aexit__
    await self._connection.stop_async()
  File "/Users/tiemo/Workspace/playwright_bug/venv12/lib/python3.12/site-packages/playwright/_impl/_connection.py", line 285, in stop_async
    self.cleanup()
  File "/Users/tiemo/Workspace/playwright_bug/venv12/lib/python3.12/site-packages/playwright/_impl/_connection.py", line 297, in cleanup
    callback.future.set_exception(self._closed_error)
asyncio.exceptions.InvalidStateError: invalid state

Additional context

Below code reliably reproduces the error:

import asyncio

from playwright.async_api import async_playwright


async def raise_exception():
    raise ValueError("Something went wrong")


async def use_playwright():
    async with async_playwright() as sp:
        browser = await sp.chromium.launch()
        page = await browser.new_page()
        await page.goto("https://example.com")

        async with asyncio.TaskGroup() as group:
            group.create_task(page.locator("css=h1").inner_text())
            group.create_task(raise_exception())


asyncio.run(use_playwright())

Environment

- OS: macOs 15
- CPU: Apple M1
- Python version: 3.12.5
- Browsers: Chromium
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
2 participants