Introduction
"Error: browserType.launch: Executable doesn't exist at …\ms-playwright\chromium_headless_shell-1248\chrome-headless-shell-win64\chrome-headless-shell.exe" means Playwright went to start its browser and the file wasn't there. Your code is fine. The browser build that this version of Playwright expects was never downloaded to the place it looked.
The fix is usually one command, but the error keeps coming back in CI, Docker and serverless deploys, because the reason is easy to miss: each Playwright version needs its own browser build, and the number in the path says which. This page reproduces the error on 13 October 2026 by upgrading Playwright from 1.63.0 to 1.64.0 with one browser cache, on Windows 11 with Node.js 20.20.2, and checks each fix.
The repro
We used an empty browser cache folder of our own, set with PLAYWRIGHT_BROWSERS_PATH, so the run didn't touch the machine's normal cache. Paths below are shortened to …\pwcache.
The project is one config and one test. playwright.config.ts:
import { defineConfig } from "@playwright/test";
export default defineConfig({
testDir: "./tests",
reporter: "list",
projects: [{ name: "chromium", use: { browserName: "chromium" } }],
});tests/smoke.spec.ts:
import { test, expect } from "@playwright/test";
test("opens a page", async ({ page }) => {
await page.setContent("<h1>Hello</h1>");
await expect(page.getByRole("heading", { name: "Hello" })).toBeVisible();
});With @playwright/test 1.63.0, npx playwright install chromium downloaded two Chromium builds into the cache, and the test passed:
chromium-1243
chromium_headless_shell-1243
ffmpeg-1011
winldd-1007Then we upgraded with npm i -D @playwright/[email protected], and ran the test again without installing anything:
Running 1 test using 1 worker
x 1 [chromium] › tests\smoke.spec.ts:3:5 › opens a page (7ms)
1) [chromium] › tests\smoke.spec.ts:3:5 › opens a page ───────────────────────────────────────────
Error: browserType.launch: Executable doesn't exist at …\pwcache\chromium_headless_shell-1248\chrome-headless-shell-win64\chrome-headless-shell.exe
╔════════════════════════════════════════════════════════════╗
║ Looks like Playwright was just installed or updated. ║
║ Please run the following command to download new browsers: ║
║ ║
║ npx playwright install ║
║ ║
║ <3 Playwright Team ║
╚════════════════════════════════════════════════════════════╝The test failed in 7 ms, before any browser started. The cache still held build 1243, and Playwright 1.64.0 asked for 1248.
Where the number in the path comes from
The folder name is the browser name and a revision: chromium_headless_shell-1248. Each playwright-core release lists the revisions it was built against in node_modules/playwright-core/browsers.json. In 1.64.0 the Chromium entries were:
[
{ "name": "chromium", "revision": "1248", "installByDefault": true, "browserVersion": "156.0.8078.4", "title": "Chrome for Testing" },
{ "name": "chromium-headless-shell", "revision": "1248", "installByDefault": true, "browserVersion": "156.0.8078.4", "title": "Chrome Headless Shell" }
]npx playwright install --dry-run chromium prints the same thing without downloading, so you can check what a project needs:
Chrome for Testing 156.0.8078.4 (playwright chromium v1248)
Chrome Headless Shell 156.0.8078.4 (playwright chromium-headless-shell v1248)For the 1.63.0 project it said Chrome for Testing 153.0.8010.12 (playwright chromium v1243). So the revision follows the playwright-core that is actually installed in node_modules, which is whatever your lockfile resolved, not the range in package.json. Our project said "^1.63.0" before the upgrade, a range that 1.64.0, the latest release that day, also satisfies; without the lockfile, a fresh install could resolve to it and ask for 1248.
Two more things in the path are worth reading:
- Which build. Our headless run looked for
chromium_headless_shell-…; the full browser is inchromium-…. A plainnpx playwright install chromiumdownloaded both. - Which folder. The start of the path is the cache Playwright searched: by default
%USERPROFILE%\AppData\Local\ms-playwrighton Windows,~/Library/Caches/ms-playwrighton macOS and~/.cache/ms-playwrighton Linux, orPLAYWRIGHT_BROWSERS_PATHif it's set (Playwright's browsers documentation). The default is inside the home folder, so browsers installed as one user are not where Playwright looks when the tests run as another.
The fix: install from the project
In the 1.64.0 project, npx playwright install chromium downloaded build 1248 (197.5 MiB for Chrome for Testing, 118.1 MiB for the headless shell) and removed the old ones:
Removing unused browser at …\pwcache\chromium-1243
Removing unused browser at …\pwcache\chromium_headless_shell-1243
Removing unused browser at …\pwcache\ffmpeg-1011
Downloading Chrome for Testing 156.0.8078.4 (playwright chromium v1248) from https://cdn.playwright.dev/builds/cft/156.0.8078.4/win64/chrome-win64.zip
…The test then passed. The removal is Playwright's cleanup: it records which projects use the cache, in a .links folder inside it, and deletes builds no project needs. To check that, we added a second project on 1.63.0 that used the same cache. Before its own install it failed the same way, now looking for chromium_headless_shell-1243, which the first project's install had removed. After npx playwright install chromium in the second project, the cache held both revisions, .links had two entries, and a later install in the first project removed nothing. Both projects' tests passed. So two projects on different Playwright versions can share a cache, as long as each has run its own install.
Install before npm ci, and you get the wrong browser
npx playwright install uses the Playwright in the project's node_modules. If there isn't one yet, npx fetches the latest Playwright and uses that. In the 1.63.0 project, with node_modules deleted:
== before npm ci
Version 1.64.0
Chrome for Testing 156.0.8078.4 (playwright chromium v1248)
Chrome Headless Shell 156.0.8078.4 (playwright chromium-headless-shell v1248)
== after npm ci
Version 1.63.0
Chrome for Testing 153.0.8010.12 (playwright chromium v1243)
Chrome Headless Shell 153.0.8010.12 (playwright chromium-headless-shell v1243)Before npm ci, npx playwright --version printed 1.64.0, and the install would have fetched build 1248, which this project can't use. After npm ci it was the project's 1.63.0 and build 1243. A CI job or Dockerfile that installs browsers in a step before the dependencies, or in a different folder, ends up with the latest Playwright's browsers and fails with this error as soon as the latest version is newer than yours.
This site's own CI runs npm ci first, then npx playwright install --with-deps chromium in the project folder, on every run, without caching browsers.
CI and Docker
Don't restore a browser cache from another Playwright version. A cache restored by a CI job is the same situation as our upgrade: the folder holds the old revision, and the new Playwright asks for the new one. Playwright's CI documentation says caching browser binaries is not recommended, because restoring the cache takes about as long as downloading again, and that if you cache them anyway the key should include the Playwright version. The version that decides the revision is the installed one, which this prints:
node -p "require('playwright-core/package.json').version"Install where the tests run. If the install runs in one environment and the launch in another (a separate build step, another user, another container), the path in the error is in a folder the install never wrote to. Install in the same environment as the run, or point PLAYWRIGHT_BROWSERS_PATH at a folder both use. Playwright's browsers documentation also describes PLAYWRIGHT_BROWSERS_PATH=0, which installs the browsers inside node_modules; we didn't run that variant here.
Docker: match the image to the project. Microsoft's Playwright images, such as mcr.microsoft.com/playwright:v1.64.0-noble, contain the browsers for one Playwright version. Playwright's Docker documentation says that if the image's version doesn't match the project's, Playwright can't find the browser executables. We set out to show that with the 1.64.0 project in the 1.63.0 and 1.64.0 images, but couldn't: Docker on our test machine failed to pull the images (its disk was full), so that part is documented, not measured here. Pin the image tag to the exact version in your lockfile, and update both together.
How to prevent it
- Install browsers after the dependencies, from the project.
npm ci, thennpx playwright install(add--with-depson Linux CI for the system libraries). - Pin Playwright exactly, or commit the lockfile. Then the revision only changes when you change it.
- Treat a Playwright upgrade as a browser upgrade. Every version bump needs a new install, locally, in CI and in your Docker base image.
- When you see the error, read the path. The revision tells you which Playwright wanted it, the build name tells you which browser, and the folder tells you which cache was searched. Compare with
npx playwright install --dry-runin the same environment.
Exercise
In a project on Playwright 1.64.0, run npx playwright install --dry-run chromium and note the revision. Then npm i -D @playwright/[email protected] and run it again. Predict what npx playwright install chromium will remove from your cache, and what a second project still on 1.64.0 would need afterwards, then check.
If the browser starts and closes again before your test is done, the error is a different one: see Target page, context or browser has been closed. If the launch works but a step runs out of time, see timeout errors. Our CI/CD guide shows a full pipeline.
Conclusion
"Executable doesn't exist" means the browser build this Playwright version needs isn't in the cache it searched. The revision in the path comes from the installed playwright-core, and it changes with every Playwright version: 1243 for 1.63.0, 1248 for 1.64.0. Run npx playwright install from the project after npm ci, don't reuse a browser cache across versions, keep Docker images on the same version as the lockfile, and read the path in the error: it says which version, which browser and which folder.
Sources and further reading
- Playwright: Browsers, on install locations,
PLAYWRIGHT_BROWSERS_PATHand removal of unused builds. - Playwright: Continuous integration, on installing browsers in CI and why caching them isn't recommended.
- Playwright: Docker, on the official images and matching their version.
- Playwright: Release notes, which list the browser versions each release ships with.