Context
Found while fixing #73 (#58, CI on Node latest). pnpm exec playwright install chromium hangs forever on Node 26 with the pinned playwright: 1.56.1. The download finishes, and then the zip extraction never resolves.
Root cause. playwright-core 1.56.1 through 1.59.x bundles yauzl's fd-slicer ReadStream. That stream sets this.destroyed = true and then calls push(null), while compressed data may still be buffered behind an inflateRaw pipe that has paused it for backpressure. Node 26.1.0 shipped nodejs/node#62557, "stream: noop pause/resume on destroyed streams". The pipe's resume() on drain is now a no-op, so the last buffered bytes never flow, end never fires, and extract() never settles. Node 22.22.0, 24.21.0 and 25.9.0 are unaffected. Any large deflated entry triggers it, and a Chromium zip always is one.
playwright-core 1.60.0 and later no longer set destroyed there (bundled yauzl 3.3.2+). I reproduced the hang with playwright-core 1.56.1's own oopDownloadBrowserMain.js against a local 5 MB deflated zip on Node 26.11.1, and confirmed that 1.64.0 completes. Minimal repro:
const { Readable } = require('stream');
const r = new Readable({ read() {} });
r.push(Buffer.alloc(10)); r.pause();
r.destroyed = true; r.push(null);
r.on('end', () => console.log('end ok'));
r.resume(); // Node 22, 25, 24.18+: 'end ok'. Node >= 26.1.0 (and 24.16-24.17): never ends.
PR #73 works around this for CI only. It runs the Chromium install step on Node 24 and then switches back to latest for every gate.
Scope
- Bump the
playwright catalog pin to at least 1.60.0, which means a Chromium revision of at least 1223. This should happen together with the agent-session image, which pre-installs only chromium-1194. That coupling is documented on the playwright catalog entry and in .github/dependabot.yml, so it is an owner decision.
- Then delete the Node 24 setup-node pair around "Install Chromium for the browser suite" in
.github/workflows/ci.yml.
Done when
- The CI Chromium install runs on Node
latest, and no workflow pins another Node major.
Correction (from the PR #73 review): nodejs/node#62557 landed in Node 26.1.0 (2026-05-07), not 26.0.0. It was also backported to Node 24.16.0 and reverted in 24.18.0 (nodejs/node#63834), so 24.16 and 24.17 hang too. That upstream revert is a second way this pin could go away, if 26.x reverts as well. The CI pin node-version: 24 resolves to the runner's cached 24.x, which is 24.18 or later on current images.
Generated by Claude Code
Context
Found while fixing #73 (#58, CI on Node
latest).pnpm exec playwright install chromiumhangs forever on Node 26 with the pinnedplaywright: 1.56.1. The download finishes, and then the zip extraction never resolves.Root cause. playwright-core 1.56.1 through 1.59.x bundles yauzl's fd-slicer
ReadStream. That stream setsthis.destroyed = trueand then callspush(null), while compressed data may still be buffered behind aninflateRawpipe that has paused it for backpressure. Node 26.1.0 shipped nodejs/node#62557, "stream: noop pause/resume on destroyed streams". The pipe'sresume()ondrainis now a no-op, so the last buffered bytes never flow,endnever fires, andextract()never settles. Node 22.22.0, 24.21.0 and 25.9.0 are unaffected. Any large deflated entry triggers it, and a Chromium zip always is one.playwright-core 1.60.0 and later no longer set
destroyedthere (bundled yauzl 3.3.2+). I reproduced the hang with playwright-core 1.56.1's ownoopDownloadBrowserMain.jsagainst a local 5 MB deflated zip on Node 26.11.1, and confirmed that 1.64.0 completes. Minimal repro:PR #73 works around this for CI only. It runs the Chromium install step on Node 24 and then switches back to
latestfor every gate.Scope
playwrightcatalog pin to at least 1.60.0, which means a Chromium revision of at least 1223. This should happen together with the agent-session image, which pre-installs onlychromium-1194. That coupling is documented on theplaywrightcatalog entry and in.github/dependabot.yml, so it is an owner decision..github/workflows/ci.yml.Done when
latest, and no workflow pins another Node major.Correction (from the PR #73 review): nodejs/node#62557 landed in Node 26.1.0 (2026-05-07), not 26.0.0. It was also backported to Node 24.16.0 and reverted in 24.18.0 (nodejs/node#63834), so 24.16 and 24.17 hang too. That upstream revert is a second way this pin could go away, if 26.x reverts as well. The CI pin
node-version: 24resolves to the runner's cached 24.x, which is 24.18 or later on current images.Generated by Claude Code