microsoft / microsoft/Webwright

Memory leak: page.on() event listeners never removed on close

Open Beginner friendly
#57 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
6k
Forks
384
PR merge metrics
No merged PRs in 30d

Description

Description

In local_browser.py, _attach_page_listeners() (line 370-372) registers page.on('console', ...) and page.on('pageerror', ...) handlers, but these are never removed in _close_async() (line 533).

The _close_async() method nullifies the self._page reference (line 541) but never calls page.remove_listener(). The Playwright pyee event emitter retains references to the bound methods, creating a memory leak.

Impact

  • Over long agent runs, listener references accumulate
  • Each listener closure captures the bound method, preventing GC
  • Memory grows linearly with agent steps
  • This is a known pattern - the Playwright Python repo has multiple confirmed reports of memory leaks from orphaned page.on() handlers

Suggested Fix

Store the listener removal in a cleanup list and call _detach_page_listeners() at the start of _close_async():

def _attach_page_listeners(self, page):
    def on_console(msg): self._on_console_message(msg)
    def on_page_error(err): self._on_page_error(err)
    page.on("console", on_console)
    page.on("pageerror", on_page_error)
    self._page_cleanup = [
        lambda: page.remove_listener("console", on_console),
        lambda: page.remove_listener("pageerror", on_page_error),
    ]

def _detach_page_listeners(self):
    for cleanup in self._page_cleanup:
        try:
            cleanup()
        except Exception:
            pass
    self._page_cleanup = []

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read local_browser.py around _attach_page_listeners() at lines 370-372 and _close_async() at line 533, then trace how self._page is cleared at line 541. Confirm the console and pageerror handlers are detached during close and that cleanup state is cleared, with no listener-removal errors escaping.

Written by the indexing model from the issue text.

Assessment

Tech stack
playwright, python
Domain
tooling
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.