#14760·puppeteer

[Bug]: Protocol timeout when screenshotting in pretty weird case (Docker + multiple tabs + networkidle2)

Author: nicofffCreated Mar 9, 2026Updated Jul 13, 2026
LabelsconfirmedP2

Minimal, reproducible example

import puppeteer from 'puppeteer-core';

const browser = await puppeteer.launch({
  protocolTimeout: 20_000,
  executablePath: process.env.CHROME_BIN || '/usr/bin/chromium',
  args: ['--no-sandbox', '--disable-gpu'],
});

const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

async function screenshotTask(id) {
  await sleep(Math.random() * 3000);
  const page = await browser.newPage();
  await page.setViewport({ width: 1024, height: 768 });
  await page.goto('https://cf.nearpod.com/neareducation/new/Scrubber/en/dash-slideEditor.png', { waitUntil: 'networkidle2'  }); // Some random image on our CDN
  console.log(`[tab${id}] taking screenshot`);
  await page.screenshot();
  console.log(`[tab${id}] done`);
  await page.close();
}

await Promise.all(Array.from({ length: 5 }, (_, i) => screenshotTask(i)));
await browser.close();

Background

This is a very weird combination of factors leading to this issue, posting it here more in case it helps to unveil some underlying issue than expecting it to be solved for my use case.

We have a puppeteer service we use for taking screenshots of internal pages. It runs in K8s. A few months back (And I wish I could give you a better answer for what version of pptr / chrome caused the issue), we started seeing the healthchecks starting to fail a lot more than they used to. Our healthcheck just attempts to load a PNG loaded in our CDN and screenshot that (more as a test that the browser instance is still alive than anything else). While trimming it down to a repro case, I discovered that this only happens: a. In docker (I couldn't repro it running node directly) b. When using multiple tabs at once (ie: handling request in parallel to the healthcheck running) c. When the thing being screenshotted is an image (Couldn't repro it by hitting a regular webpage) d. Only when using waitUntil: 'networkidle2' on the goTo call.

Created a repo with the full repro case (including dockerfile here: https://github.com/nicofff/puppeteer_repro_weird_hang)

Expectation

Screnshots succeed

Reality

file:///app/node_modules/puppeteer-core/lib/esm/puppeteer/common/CallbackRegistry.js:99 #error = new ProtocolError(); ^

ProtocolError: Page.captureScreenshot timed out. Increase the 'protocolTimeout' setting in launch/connect calls for a higher timeout if needed. at <instance_members_initializer> (file:///app/node_modules/puppeteer-core/lib/esm/puppeteer/common/CallbackRegistry.js:99:14) at new Callback (file:///app/node_modules/puppeteer-core/lib/esm/puppeteer/common/CallbackRegistry.js:103:16) at CallbackRegistry.create (file:///app/node_modules/puppeteer-core/lib/esm/puppeteer/common/CallbackRegistry.js:22:26) at Connection._rawSend (file:///app/node_modules/puppeteer-core/lib/esm/puppeteer/cdp/Connection.js:104:26) at CdpCDPSession.send (file:///app/node_modules/puppeteer-core/lib/esm/puppeteer/cdp/CdpSession.js:71:33) at CdpPage._screenshot (file:///app/node_modules/puppeteer-core/lib/esm/puppeteer/cdp/Page.js:834:62) at CdpPage.screenshot (file:///app/node_modules/puppeteer-core/lib/esm/puppeteer/api/Page.js:1079:41) at async CdpPage. (file:///app/node_modules/puppeteer-core/lib/esm/puppeteer/util/decorators.js:164:24) at async screenshotTask (file:///app/index.mjs:17:3) at async Promise.all (index 2)

Puppeteer configuration file (if used)

Puppeteer version

24.38.0

Node version

v24.4.1

Package manager

npm

Package manager version

11.4.2

Operating system

Linux