[Windows] Visible console window per render shot: 0.8.44 resolves @puppeteer/browsers 3.2.1, where detached defeats windowsHide (fixed upstream in 3.2.2)

Author: andycfchenCreated Sep 17, 2026Updated Sep 17, 2026

Summary

On Windows, every hyperframes render opens a visible console window per browser launch (78 shots = 78 windows), stealing focus and making the machine unusable for anything else during a render.

This is not one of the windowsHide gaps already tracked in #3476 / #3500 / #3851 / #3960 / #3996 — those all cover hyperframes' own spawns. This one comes from @puppeteer/browsers, and it is already fixed upstream. 0.8.44 just resolves to the one broken version.

Root cause

[email protected] declares "puppeteer-core": "^25.8.0". In practice that resolved here to [email protected]@puppeteer/[email protected].

@puppeteer/[email protected] lib/launch.js spawns the browser with both flags:

javascript
opts.detached ??= true;          // line 157
...
childProcess.spawn(this.#executablePath, this.#args, {
  detached: opts.detached,       // line 173
  windowsHide: true,             // line 174
  ...
});

On Windows libuv ORs DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP (from detached) together with CREATE_NO_WINDOW (from windowsHide) into the CreateProcessW creation flags. Those are mutually exclusive: DETACHED_PROCESS wins, the child inherits no console, and chrome-headless-shell.exe — a console-subsystem binary (IMAGE_SUBSYSTEM_WINDOWS_CUI) — gets a freshly allocated, visible console. windowsHide: true is dead code in that combination.

Upstream: puppeteer/puppeteer#15410, introduced by #15339, reverted by #15415, released in @puppeteer/[email protected].

Evidence

Controlled A/B on the same binary, same machine, only detached differs. External EnumWindows + IsWindowVisible monitor sampling at 25 ms:

MODE=detached  ({detached:true,  windowsHide:true})  browser procs=4  NEW visible windows=1  <- class=ConsoleWindowClass proc=chrome-headless-shell
MODE=hidden    ({detached:false, windowsHide:true})  browser procs=4  NEW visible windows=0

Live capture during an actual hyperframes render, before any workaround:

class=CASCADIA_HOSTING_WINDOW_CLASS  proc=WindowsTerminal
class=PseudoConsoleWindow            proc=chrome-headless-shell
class=CASCADIA_HOSTING_WINDOW_CLASS  proc=WindowsTerminal
class=PseudoConsoleWindow            proc=chrome-headless-shell

(There is a second, independent aggravating factor worth knowing about: when Windows' Default terminal application is Windows Terminal — the Windows 11 default — the console handoff ignores CREATE_NO_WINDOW entirely, so console children pop a real Windows Terminal window even where windowsHide is correctly set. Switching to Console Host removes that layer; the @puppeteer/browsers bug above survives the switch and still produces ConsoleWindowClass windows.)

Environment

Suggested fix

Require puppeteer-core >= 25.10.0 (the first release that pulls @puppeteer/[email protected]). ^25.8.0 silently permits the one broken version. #3933 already bumps @puppeteer/browsers to 3.2.2 — this is the reason it matters on Windows.

Workaround for anyone hitting this now

Patch the resolved copy in the npx cache, @puppeteer/browsers/lib/launch.js:

javascript
- opts.detached ??= true;
+ opts.detached ??= process.platform !== 'win32';

Verified: renders run with zero new visible windows afterwards.