Skip to content

fix(chromium): retry screenshot when page navigates away mid capture - #43721

Closed
Adarsh (jackeddisciple) wants to merge 1 commit into
microsoft:mainfrom
jackeddisciple:fix-43685
Closed

Adarsh (jackeddisciple) wants to merge 1 commit into
microsoft:mainfrom
jackeddisciple:fix-43685

Conversation

@jackeddisciple

@jackeddisciple Adarsh (jackeddisciple) commented Oct 28, 2026 •

Copy link
Copy Markdown

Summary

In Chromium, page.screenshot() can hang until timeout when the main frame commits a new document while Page.captureScreenshot is in flight. With slightly different timing it throws Protocol error (Page.captureScreenshot): Not attached to an active page instead. This is what makes SS-027 time out in the Java port.

Root cause

  • Page.captureScreenshot asks the widget of the current document to draw a frame (ForceRedraw). If that document is destroyed before it draws, the callback is dropped together with the widget and no response is ever sent. Playwright turns bfcache off, so a document that navigates away is always destroyed. Chromium bug: https://issues.chromium.org/issues/578475983
  • DevTools moves to the new frame host at ReadyToCommitNavigation. A capture that lands between that point and the commit fails the active host check with Not attached to an active page.

Fix

  • Race the capture against a main frame commit (InternalFrameNavigatedToNewDocument). If the commit wins, drop the old capture and run takeScreenshot again, so the layout metrics and the clip come from the new document.
  • Handle Not attached to an active page the same way.
  • The retry does not spin. Chromium holds renderer bound commands like Page.getLayoutMetrics until the navigation finishes, so the next attempt only runs once the new document is in place. The call timeout still applies, so an endless redirect loop ends in a normal timeout.
  • documentRect is no longer mutated, so a retried viewport screenshot uses the scroll position of the new document.
  • Keeps the "never throw because the page is navigating" behavior from fix(screenshot): never throw page is navigating #6103.

Regression test

SS-097 stalls one-style.css, so one-style.html never renders and the capture stays pending until the page navigates away after 500 ms. On main it times out with the call log ending at "fonts loaded". It is skipped on WebKit, which captures the blocked page right away.

Notes

  • Not covered: Unable to capture screenshot when a capture lands before a fresh document has drawn its first frame. Main does the same and it fails fast, so I left it alone. Retrying it would turn a fast error into a full timeout for pages that never draw.
  • If the commit event arrives just after the capture already went to the new document, the old capture still finishes and overlaps the retry. Overlapping full page captures can leave window.outerWidth/outerHeight at the clip size on the headless shell, while the viewport, pixels and input stay correct. The timing window is tiny, and today the same timing can hang.
  • [Bug]: Page.screenshot hangs when main resource does not finish #9757 (main resource never finishes) is unchanged.

Fixes #43685

@dgozman

Copy link
Copy Markdown
Collaborator

I am not sure retrying is the right fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Page.captureScreenshot never returns in Chromium when the page navigates away right after it is sent

2 participants