Skip to content

fix(screenshot): fall back to CDP capture when captureVisibleTab fails - #83

Merged
BB-fat merged 1 commit into
mainfrom
fix/71-screenshot-fallback
Aug 12, 2026
Merged

fix(screenshot): fall back to CDP capture when captureVisibleTab fails#83
BB-fat merged 1 commit into
mainfrom
fix/71-screenshot-fallback

Conversation

@BB-fat

@BB-fat BB-fat commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Motivation

Refs #71 — on some Windows + Chrome 151 setups, bsk screenshot always fails with Failed to capture tab: image readback failed. That error string is produced inside Chromium (FAILURE_REASON_READBACK_FAILED in chrome/browser/extensions/api/tabs/tabs_api.cc): the browser's compositor fails to read the window surface back into a bitmap, so chrome.tabs.captureVisibleTab rejects and no image data ever reaches the extension. The full-tab screenshot path had no fallback, so a browser-side readback failure surfaced as a hard error.

Changes

  • Extension (apps/extension/src/tools/observation.ts): full-tab capture now falls back to CDP Page.captureScreenshot (format: "png", fromSurface: true) when captureVisibleTab rejects. The CDP path captures through the renderer's BeginFrame pipeline instead of the window-surface readback that captureVisibleTab depends on. Overlay suppression (withOverlaysHiddenForCapture) wraps both attempts, and the CDP session is attached the same way the existing --ref element-capture path does it. When both paths fail, the error carries data.reason = "screenshot_capture_failed" and both underlying messages.
  • CLI (crates/bsk-cli/src/cli/render_error.rs): new screenshot_capture_failed reason override for cdp_failed with a hint that points at the browser-side rendering/readback cause (reload tab / restart browser / upgrade or downgrade Chrome) instead of the generic "stuck DevTools session" copy.
  • Tests: vitest cases for (1) primary failure → CDP fallback succeeds with the expected Page.captureScreenshot params, (2) both paths fail → cdp_failed + screenshot_capture_failed reason + both messages, (3) primary success never touches CDP; a Rust unit test locking the new reason-override copy.

Notes / honesty

The underlying readback regression is inside the browser, so this PR is a mitigation: it routes around the broken capture path rather than fixing it. The exact Chromium 151 change that breaks surface readback on the reporter's machine still needs verification on a real Windows environment.

Test plan

  • pnpm --filter @browser-skill/extension compile
  • pnpm ext:test (618 passed)
  • pnpm lint
  • cargo fmt --all -- --check, cargo clippy --workspace --all-targets --locked -- -D warnings, cargo test --workspace --locked

chrome.tabs.captureVisibleTab reads back the window surface, which fails
outright on some Windows/Chrome combinations (Chromium
FAILURE_REASON_READBACK_FAILED: "Failed to capture tab: image readback
failed"), leaving full-tab screenshots without any working path.

Capture the full tab via CDP Page.captureScreenshot (fromSurface) when
the visible-tab capture rejects; the CDP path goes through the
renderer BeginFrame pipeline instead of the surface readback. When both
paths fail, return cdp_failed with data.reason=screenshot_capture_failed
carrying both underlying messages, and render a CLI hint that points at
the browser-side readback cause.

Refs #71
@BB-fat
BB-fat merged commit f81a1e7 into main Aug 12, 2026
4 checks passed
@BB-fat
BB-fat deleted the fix/71-screenshot-fallback branch August 12, 2026 14:10
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.

1 participant