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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions