TurnSignal

Playwright "worker process exited unexpectedly": causes and fixes

By TurnSignal · October 6, 2026 · 5 min read

In short

  • Playwright prints Error: worker process exited unexpectedly (code=…, signal=…) when a worker process died without the runner asking it to stop.
  • The test that was running fails with that error. Playwright starts a new worker for the remaining tests, and retries the failed one if retries are on.
  • Read the code and signal: signal=SIGKILL usually means the process was killed from outside, most often for running out of memory. A numeric exit code with signal=null usually means something called process.exit() or Node crashed.
  • Fix the cause (memory, workers, a leaking test, process.exit in test code), and watch for a bigger version of the same problem: a whole CI runner killed, where results disappear instead of failing.

What the error means

Playwright Test runs your tests in worker processes: separate OS processes, each with its own browser, orchestrated by the test runner. When the runner wants a worker to stop, it asks it to. If a worker process ends on its own instead, the runner reports:

Error: worker process exited unexpectedly (code=null, signal=SIGKILL)

In Playwright 1.63 the runner fails the test that was running at that moment with this error and moves the rest of that worker's tests to a new worker. If you have retries set, the failed test is retried like any other failure. If no test was running, for example when the worker died while setting up or tearing down a worker fixture, the error is reported against the next test that worker was going to run.

The error is a symptom. It tells you the process died, not why. The code and signal values are the first clue.

Reading code and signal

Node reports either an exit code or the signal that killed the process, and Playwright prints both:

  • `signal=SIGKILL`: the process was killed from outside and could not clean up. On Linux CI machines and in containers the usual sender is the out-of-memory killer. A CI log that shows exit code 137 for a step is the same thing seen from the shell: 128 + 9, and 9 is SIGKILL.
  • `signal=SIGSEGV` or `SIGABRT`: the process crashed. Native modules, a broken Node install or an incompatible binary are typical.
  • `signal=SIGTERM` or `SIGINT`: something asked the process to stop, for example a CI job being cancelled or a timeout in the CI system itself.
  • `code=1` (or another number) with `signal=null`: the process exited by itself. Look for process.exit() in test code, helpers or a library, or an uncaught error in code that runs outside a test.

Cause 1: running out of memory

This is the most common cause in CI. Each worker starts its own browser, so memory use grows roughly with the number of workers. A suite that is fine on a laptop with 32 GB can be killed on a 7 GB CI runner, and the worker that happens to cross the line gets the SIGKILL.

Things to try, cheapest first:

  1. Lower workers in CI, for example workers: process.env.CI ? 2 : undefined, and see whether the error disappears. If it does, it was memory.
  2. In Docker, run Chromium with --ipc=host. Playwright's Docker guide says that without it, Chromium can run out of memory and crash. Also use --init, which the same guide recommends to avoid zombie processes.
  3. Look for a test that leaks: pages or contexts opened in a loop and never closed, huge downloads kept in memory, or a test that loads a very heavy page many times. Run the suspect file with --repeat-each and watch memory.
  4. Use a bigger runner, or split the suite across more shards so each machine runs fewer tests.
// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  workers: process.env.CI ? 2 : undefined,
  retries: process.env.CI ? 2 : 0,
});

Cause 2: process.exit() or a crash outside a test

Code that calls process.exit() ends the worker immediately. It can hide in a helper ("exit if the environment variable is missing"), in a global setup imported by a test file, or in a third-party library. Search your test code and helpers for process.exit first. Throw an error instead; Playwright then reports it against the right test and keeps the worker alive.

Cause 3: the CI system stopped the job

When the CI job hits its own time limit or is cancelled, the CI system sends signals to the processes in the job. Workers can report SIGTERM or SIGINT before the main process stops. In this case the fix is in the CI configuration (the job timeout) or in making the suite faster, for example by sharding.

How to find which test was responsible

The test that fails with the error is the one that was running when the worker died, which is not always the one that used the memory. Memory builds up over every test that worker ran. Useful steps:

  • Look at which tests ran in the same worker before the crash. Reporters receive the worker index for each attempt, and the list reporter output shows the order.
  • Run that file alone with --workers=1 --repeat-each=10 and watch the process memory in another terminal.
  • Check the CI machine's memory graph or the kernel log (dmesg) if your CI gives you access; the out-of-memory killer logs the process it killed.

When the whole runner dies

The same problem one level up is worse. If the out-of-memory killer, a spot-instance shutdown or a job timeout kills the whole CI machine, the Playwright runner itself dies with the workers. Then nothing reports the tests that never ran. A sharded run simply shows fewer tests than it should, and the run can even look green. The guide to missing tests after a crashed shard covers how to notice that gap.

TurnSignal is built for this case. The reporter writes results to disk in CI as tests finish, records memory on the machine while the run is going, and compares what reported with the list of tests the run planned. Tests from a runner that stopped responding are listed as Missing with the likely reason, instead of disappearing, and a failure caused by a worker or browser crash is labelled as a crash, with a note when the machine was nearly out of memory. The reporter never changes your exit code. Setup is one line next to your existing reporters; see the docs.

Questions people ask

What does "worker process exited unexpectedly" mean in Playwright?

A worker process (the OS process that runs tests and its browser) ended without the runner asking it to stop. The running test fails with this error and the remaining tests move to a new worker.

What does signal=SIGKILL mean?

The process was killed from outside and could not clean up. In CI and containers this is usually the out-of-memory killer. Lower the number of workers to confirm.

Will retries fix it?

Retries can turn the run green, because the retried test runs in a fresh worker. If the cause is memory, the crash will come back as the suite grows; fix the memory use or the worker count.

Why does the error appear on a test that does nothing heavy?

Memory builds up across every test the worker ran. The test that fails is the one running when the limit was crossed, which may not be the one that used the memory.

Sources

Playwright details were checked against Playwright 1.63 and its documentation on October 6, 2026.

Try TurnSignal on your next run

Add one reporter line next to your existing reporters. Free to start, no credit card, no repository access.

Get started free Read the docs