Commit 5a9a09d
ci: skip puppeteer postinstall download to avoid Chrome race on Node 24 (#912)
## What
Set `PUPPETEER_SKIP_DOWNLOAD=1` on the `pnpm install` step in the `Build
& Test` matrix, so puppeteer's postinstall doesn't try to download
Chrome. The dedicated `Install Chrome for puppeteer` step (already in
the workflow) keeps doing the download synchronously and reliably.
## Why
Node 24 jobs have been failing intermittently with:
```
BrowserLaunchError: Failed to launch browser
Caused by: Could not find Chrome (ver. 146.0.7680.153).
```
Step timing shows the `Install Chrome for puppeteer` step has been
silently no-opping on Node 24 — exiting in ~1 s with no output, vs ~4 s
with a `chrome@146.0.7680.153 …` line on a healthy run.
### Root cause
Puppeteer's postinstall hook
([`install.mjs`](https://github.com/puppeteer/puppeteer/blob/puppeteer-v24.40.0/packages/puppeteer/install.mjs))
is **fire-and-forget**:
```js
const {downloadBrowsers} = await importInstaller();
downloadBrowsers(); // ← not awaited
```
Inside, `downloadBrowsers()` kicks off downloads for chrome,
chrome-headless-shell, and firefox in parallel. When `pnpm install`
returns before they finish, the process is reaped mid-download and
`~/.cache/puppeteer/chrome/linux-146.0.7680.153/` is left
half-populated.
The next step then runs `pnpm exec puppeteer browsers install chrome`,
which hands off to `@puppeteer/browsers`. That library's "already
installed" check is purely "does this directory exist with the right
buildId?" — so it sees the half-written directory, assumes Chrome is
installed, and exits silently. Tests then explode at runtime because the
binary isn't actually there.
That explains everything we observed:
- **Only Node 24** — probably just timing; Node 24's faster startup
loses the race more often.
- **Intermittent** — it's a literal race between `pnpm install`
returning and the download completing.
- **Retries sometimes work** — when the download happens to finish in
time, no orphaned directory, all green.
- **Has been a slow-burn issue** — but the Renovate/TS-v6 lockfile bumps
that invalidate the pnpm-store cache made the race lose more often.
### Fix
`PUPPETEER_SKIP_DOWNLOAD=1` on the install step makes puppeteer's
postinstall log "Skipping downloading browsers as instructed" and return
immediately — no racy background download, no orphaned cache directory.
The explicit step that follows then performs the download synchronously
and reliably.
Credit to @barjin for [suggesting this
approach](#912 (comment))
— it's much cleaner than the `rm -rf ~/.cache/puppeteer` workaround in
the first commit, which only mopped up after the race instead of
preventing it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 0536f90 commit 5a9a09d
1 file changed
Lines changed: 10 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
44 | 54 | | |
45 | 55 | | |
46 | 56 | | |
| |||
0 commit comments