Repository navigation
[Bug]: Page.captureScreenshot never returns in Chromium when the page navigates away right after it is sent #43685
Description
Version
1.64.1, also main (1.65.0-next)
Steps to reproduce
Run the script below with node repro.js. Set CHANNEL=chromium or CHANNEL=chrome to use the full browser instead of the headless shell.
// Page.captureScreenshot never returns when the page navigates away right after it is sent.
// Chromium bug: https://issues.chromium.org/issues/578475983
//
// npm i playwright && npx playwright install chromium
// node repro.js
const http = require('http');
const { chromium } = require('playwright');
const pages = {
// a.html navigates to b.html as soon as it runs; b.html stays.
'/a.html': `<script>setTimeout(() => location.href = 'b.html', 1)</script>`,
'/b.html': `<div>b</div>`,
};
const server = http.createServer((req, res) => {
res.writeHead(pages[req.url] ? 200 : 404, { 'Content-Type': 'text/html' });
res.end(pages[req.url] || '');
});
server.listen(0, async () => {
const prefix = `http://localhost:${server.address().port}`;
const browser = await chromium.launch({ channel: process.env.CHANNEL });
let lost = 0;
for (let i = 0; i < 10; i++) {
const page = await browser.newPage();
const session = await page.context().newCDPSession(page);
await session.send('Page.enable');
const pending = new Set();
// Capture at each commit of the main frame, as page.screenshot() does when the call lands there.
session.on('Page.frameNavigated', ({ frame }) => {
if (frame.parentId)
return;
const path = new URL(frame.url).pathname;
pending.add(path);
session.send('Page.captureScreenshot', { format: 'png' }).then(() => pending.delete(path), () => pending.delete(path));
});
await page.goto(prefix + '/a.html');
await page.waitForURL('**/b.html');
await page.waitForTimeout(5000);
for (const path of pending) {
lost++;
console.log(`iteration ${i}: Page.captureScreenshot sent at the commit of ${path} got no response in 5 s`);
}
await page.close();
}
console.log(`${browser.version()}: ${lost} of 10 iterations lost a Page.captureScreenshot response`);
await browser.close();
server.close();
});Expected behavior
Each Page.captureScreenshot returns the image, or an error such as Not attached to an active page when the document goes away.
Actual behavior
The Page.captureScreenshot that is sent at the commit of a.html never returns, while a.html navigates to b.html:
iteration 5: Page.captureScreenshot sent at the commit of /a.html got no response in 5 s
iteration 6: Page.captureScreenshot sent at the commit of /a.html got no response in 5 s
156.0.8078.4: 5 of 10 iterations lost a Page.captureScreenshot response
| Browser | Iterations with no response |
|---|---|
| Headless shell 156.0.8078.4 | 5 of 10 |
Chromium 156.0.8078.4, channel: 'chromium' |
10 of 10 |
Chrome 156.0.8078.47, channel: 'chrome' |
10 of 10 |
When the call lands at that moment, page.screenshot() waits until its timeout.
Additional context
Chromium bug: https://issues.chromium.org/issues/578475983. It has a standalone repro with no Playwright code.
How we found it. The Java port of SS-027 should work while navigating (tests/page/page-screenshot.spec.ts) times out in Chromium on CI, and in about 1 of 6 local runs on 2 cores. The call log ends at fonts loaded. The pw:protocol log shows:
Page.captureScreenshotwas sent right after a document of the redirect loop committed, and the next navigation started.- The loop ended and the page became idle, but the call got no response for 30 seconds.
Runtime.evaluateon the same session still got responses.
The back/forward cache. The response goes missing only when the old document is destroyed instead of going into the back/forward cache:
- Playwright passes
--disable-back-forward-cache, and this switch alone is enough to reproduce. - Without it, an
unloadhandler on the old page has the same effect. - When the old page goes into the cache, Chrome answers with
Not attached to an active page.
Why upstream CI does not see it. SS-027 has no Chromium failure in the CI results database: 8689 results from 1150 runs since August 14. Before it sends Page.captureScreenshot, page.screenshot() waits for fonts and reads the layout metrics, so the call usually lands later than the commit. The Java client's timing hits the window more often. The Java port disables SS-027 in Chromium for now (microsoft/playwright-java#2024).
Possibly related:
- [Bug]: Page.screenshot hangs when main resource does not finish #9757: a screenshot hang when the main resource does not finish.
SS-091 should work if the main resource hangsis still skipped in Chromium with a link to it. - https://issues.chromium.org/40146273: "Page.captureScreenshot function call stuck when the browser sees network error".
Environment
- OS: Ubuntu 24.04, x64
- Node.js: 26.5.0
- Playwright: 1.64.1
- Browsers: Chromium 156.0.8078.4 (headless shell and full), Google Chrome 156.0.8078.47
Activity
jackeddisciple commentedon Oct 28, 2026
I’d be happy to look into this and submit a fix if nobody’s working on it already.
github-actions commentedon Oct 29, 2026
github-actions commentedon Oct 29, 2026
Hi, I'm the Playwright bot. I reproduced this on the latest checkout.
This is a Chromium bug, still present in 157.0.8103.15. Screenshot commands remain unanswered after navigation even when sent directly to Chromium without any Playwright code. Other commands on the same session still return. The browser report below adds evidence for the existing https://issues.chromium.org/issues/578475983.
Reproduction and results
Tested on Ubuntu 24.04.5 x64, Node.js 24.22.1, Playwright
1.65.0-next, commitbda54b052be6c5272557f3f1c972ad378bd1dc60.The fixture-based test serves
/a.htmlwith:/b.htmlis a static page. AfterPage.enable, the test sendsPage.captureScreenshotat every main-framePage.frameNavigatedevent, navigates to/a.htmlten times, and checks that every command receives either an image or an error. It waits 500 ms after each arrival at/b.html, then another five seconds for outstanding responses.Runtime.evaluate('location.pathname')still returns/b.html./a.htmlwere still unanswered--disable-back-forward-cacheSS-027andSS-039, Chromium, Firefox, WebKitThe direct-pipe reproduction uses only Node.js built-in modules and the browser executable. It is included in the browser report.
The first attempt to run existing coverage overlapped another test process and hit a test-server port conflict. The full six-test command was then rerun without overlap and passed.
Cause and related work
At Chromium revision
1aa07b638799e59656559ae6c6649d4b197f555e,PageHandler::CaptureScreenshotmoves its response callback into a widget snapshot request.RenderWidgetHostImplstores the pending callback and requests a redraw. Its normal widget destruction path does not fail pending snapshots, although its renderer-exit path does. The fix belongs in Chromium's pending-snapshot completion during navigation, not in the Java client.#43721 was closed without a merge; a maintainer questioned retrying as the right fix. No code from that PR was run. #9757 concerns a main resource that never finishes; this reproduction finishes both resources and leaves the destination page responsive.
The Chromium issue pages require sign-in on this runner, so I could not verify the status of the existing upstream report.
Chromium bug report, for a maintainer to file at https://crbug.com/new:
Title: Chromium: Page.captureScreenshot loses its response when the captured document navigates away
Body
Triaged on Linux by the Playwright bot - agent run