When Playwright runs out of memory, first reduce how much browser work happens at once. Launch one browser, create an isolated context per job, close that context in a finally block, and cap parallel pages. More memory only postpones a leak or unbounded queue.
Chromium uses several processes, so Node's heap is only part of the total. A container can reach its memory limit even when process.memoryUsage() in the Node parent looks acceptable.
The error text points to different memory owners
| WHAT YOU SEE | WHAT IT SUGGESTS | FIRST ACTION |
|---|---|---|
| Exit code 137 or SIGKILL | The container or operating system killed a process, often for memory pressure | Compare total container use with its limit |
| JavaScript heap out of memory | The Node process exhausted its V8 heap | Find retained JavaScript objects and unbounded results |
| Target page, context or browser has been closed | The browser closed earlier, was killed, or your code closed it | Read the lines before this secondary error |
| Browser process disappeared with no app exception | Chromium crashed outside the Node heap | Lower browser and page concurrency |
Use one browser and disposable contexts
A browser context gives each job isolated cookies and storage without paying for a new Chromium process. Playwright recommends closing created contexts before closing the browser so pages shut down cleanly.
Set a real concurrency budget
Replace an unbounded Promise.all with a queue that admits only a small number of pages. Start at one. Increase the limit while observing peak container memory and job duration. The correct number depends on the target pages, downloads, extensions, screenshots, and parsing work, so a universal value would be misleading.
- Close pages and contexts after each job, including failure paths.
- Do not retain page objects, responses, screenshots, or large HTML strings after their job finishes.
- Block images, fonts, video, and analytics requests when the result does not need them.
- Write completed output to durable storage instead of collecting an entire crawl in one array.
- Apply backpressure when jobs arrive faster than the browser can finish them.
- Use navigation and operation timeouts so a stuck page releases its slot.
Measure the parent, but remember the children
Log memory at the same points in each job: before creating a context, after closing it, and after a fixed number of jobs. A high but stable plateau means a larger plan may be justified. A line that keeps rising after every context closes needs investigation before scaling the container.
Docker has one Chromium-specific trap
When you control Docker, Playwright recommends running Chromium with host IPC because a small shared-memory area can make Chromium run out of memory and crash. That setting is a container-level choice. On a managed host where you cannot change Docker flags, reduce concurrency or choose a runtime designed for browser automation.
Choose the host after the workload is bounded
A request function fits a short screenshot or one isolated browser task. A continuous worker fits a monitor, queue consumer, or crawl loop. A browser service with many parallel sessions needs autoscaling and resource controls beyond a small single container.
Spocket's published runtime guidance places Playwright and Puppeteer on Builder or Fleet rather than Solo. It runs one continuous Node or Python process, restarts it after a crash, and keeps logs, but it does not add browser replicas. Use /run/scrapers for the hosting limits and /documentation/logs-and-status to inspect the lines before a killed process restarts.