Skip to content

[Bug]: async_playwright() leaves blocking background task if cancelled quickly #42296

Closed

Description

Version

1.62.0

Steps to reproduce

With Pythin 3.14.7 and Playwright 1.62.0:

import asyncio

from playwright.async_api import async_playwright

async def run_browser():
    async with async_playwright():
        pass

async def run():
    task = asyncio.create_task(run_browser())
    await asyncio.sleep(0.01)  # for me: some value between 0.001 and 0.3
    task.cancel()
    try:
        await task
    except asyncio.CancelledError:
        pass

asyncio.run(run())

Expected behavior

The program exits.

Actual behavior

The program hangs.

Additional context

No response

Environment

Linux 7.1.3
Python 3.14.7
playwright 1.62.0 (latest version on PyPI)

Activity

  1. sreegithub89 commented on Aug 18, 2026

    @sreegithub89

    should/have to be async with async_playwright(): in try block?

  2. sattlerc commented on Aug 18, 2026

    @sattlerc
    Author

    should/have to be async with async_playwright(): in try block?

    No. This raises a CancelledError as expected, which causes the task to be cancelled. The problem is that async_playwright().__aenter__() leaves behind some blocking background task.

  3. sreegithub89 commented on Aug 18, 2026

    @sreegithub89
    import asyncio
    from playwright.async_api import async_playwright
    
    async def run_browser():
        # Using async context manager ensures cleanup even if cancelled
        async with async_playwright() as p:
            browser = await p.chromium.launch()
            page = await browser.new_page()
            await page.goto("https://example.com")
            await browser.close()
    
    async def run():
        task = asyncio.create_task(run_browser())
        await asyncio.sleep(0.01)  # simulate early cancellation
        task.cancel()
        try:
            await task
        except asyncio.CancelledError:
            # Context manager guarantees playwright.stop() is called
            print("Task cancelled safely, no background tasks left.")
    
    asyncio.run(run())
    
    
  4. sattlerc commented on Aug 19, 2026

    @sattlerc
    Author

    That's essentially the same program. Hangs for me.

  5. sattlerc commented on Aug 19, 2026

    @sattlerc
    Author

    The async code doesn't seem easy to understand to me and possibly somewhat brittle.

    One thing that immediately stands out: the Python documentation for create_task says:

    Save a reference to the result of this function, to avoid a task disappearing mid-execution. The event loop only keeps weak references to tasks. A task that isn’t referenced elsewhere may get garbage collected at any time, even before it’s done.

    There seem to be several places where that is not the case. For example, in PlaywrightContextManager.__aenter__:

            loop.create_task(self._connection.run())
  6. yury-s commented on Aug 19, 2026

    @yury-s
    Member

    Cancelling a task that is running a Playwright call is not supported and results in undefined behavior. Documenting this in #42312. If you can reproduce a hang without task.cancel(), please open a new issue.

  7. sattlerc commented on Aug 19, 2026

    @sattlerc
    Author

    Cancelling a task that is running a Playwright call is not supported and results in undefined behavior. Documenting this in #42312. If you can reproduce a hang without task.cancel(), please open a new issue.

    That would be unfortunate. It would mean that running playwright as a task inside a TaskGroup is undefined behaviour. This is how I found this issue: starting playwright in parallel with some other task that failed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions