Skip to content

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

Description

@rahulrao85

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 = []

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