[Bug]: WebWorker.evaluate() and close() never settle when the worker script fails to load
Minimal, reproducible example
import http from 'node:http';
import puppeteer from 'puppeteer';
// A worker needs a real origin, so page.setContent() is not enough.
const server = http.createServer((req, res) => {
if (req.url === '/missing-worker.js') {
res.statusCode = 404;
res.end('not found');
return;
}
res.setHeader('content-type', 'text/html');
res.end('<!doctype html><title>repro</title>');
});
await new Promise<void>(r => server.listen(0, r));
const {port} = server.address() as {port: number};
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(`http://127.0.0.1:${port}`);
page.on('workerdestroyed', () => console.log('workerdestroyed fired'));
const workerCreated = new Promise<any>(r => page.once('workercreated', r));
await page.evaluate(() => {
new Worker('/missing-worker.js');
});
const worker = await workerCreated;
const settle = (promise: Promise<unknown>) =>
Promise.race([
promise.then(
value => `resolved: ${value}`,
error => `rejected: ${error.message}`,
),
new Promise(r => setTimeout(() => r('still pending after 10s'), 10_000)),
]);
console.log('evaluate():', await settle(worker.evaluate(() => 1 + 1)));
console.log('close():', await settle(worker.close()));
await browser.close();
server.close();Background
We found this while working on #15497. There, a dedicated worker's script request stays paused by request interception, so the script never loads. Every worker.evaluate() on that worker then hangs with no error and no timeout. The same happens whenever a dedicated worker's script fails to load, and a 404 is the simplest way to show it.
Expectation
Once the worker is destroyed (workerdestroyed fires), worker.evaluate(), worker.evaluateHandle() and worker.close() reject, like they did in 25.1.0:
workerdestroyed fired
evaluate(): rejected: Protocol error (Runtime.callFunctionOn): Target closed
close(): rejected: Execution context is not available in detached frame or worker "http://127.0.0.1:62724/missing-worker.js" (are you trying to evaluate?)Reality
workerdestroyed fires, but evaluate() and close() never settle:
workerdestroyed fired
evaluate(): still pending after 10s
close(): still pending after 10sWhere it started: this is a regression from #15099 ("fix: await for Worker script execution"), first released in 25.2.0. I got the output above on 25.2.0 and 25.12.0; 25.1.0 rejects as shown under Expectation. All three used Chrome for Testing 154.0.8037.57.
Puppeteer configuration file (if used)
Puppeteer version
25.12.0
Node version
22.16.0
Package manager
npm
Package manager version
10.9.2
Operating system
macOS
Source: puppeteer/puppeteer