Skip to content

fix(cli): snapshot gives a seek that will not settle its own --timeout, not three minutes - #6910

Merged
miguel-heygen merged 2 commits into
mainfrom
fix/snapshot-media-prep-hang
Nov 1, 2026
Merged

miguel-heygen merged 2 commits into
mainfrom
fix/snapshot-media-prep-hang

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

What

snapshot stops waiting for a seek to settle after its --timeout (default 45 s, never more than 170 s) instead of a fixed 170 s, and still names what it was waiting on.

Why

A page whose hf-seek listener never resolves (for example one awaiting a video that is not on screen) made snapshot print one progress line and then sit for 170 s before failing, whatever --timeout said. With a few stills that is past the 5 minutes a caller waits. Reproduced on the Linux devbox with a one-listener project: snapshot --at 1,3,5 --timeout 20000 took 172 s to fail on main and 22 s with this change, both with SeekNotSettledError: seek did not settle within N ms: still waiting on hf-seek.

How

settleCompositionSeek took its budget only from the protocol timeout constant (SEEK_SETTLES_BEFORE_PROTOCOL_TIMEOUT_MS). It now accepts seekSettleTimeoutMs, defaulting to that constant, and never lets it exceed that constant, so a long --timeout still ends in the named error before Chrome's 180 s protocol timeout. check, compare, layout and the others are unchanged. snapshot passes its own --timeout.

Not done: two other reports in this family (13 stills from a 4K storyboard of short HDR HEVC clips, and 20 stills after importing 19 .MOV clips) did not reproduce with synthetic equivalents on the devbox: 8 4K HDR HEVC clips took 28 s for 8 stills, 19 .MOV clips took 34 s for 20. ffprobe in that path already has a 30 s deadline. So those two may be a different cause; I have not changed anything for them.

Test plan

fails without the fix: captureCompositionFrame.test.ts "lets a caller bound how long a seek may stay unsettled" and "never lets a seek stay unsettled past the protocol timeout".

  • The test file passes 35/35 with the change; removing the option fails the first test and removing the clamp fails the second.
  • oxfmt check clean on packages/cli/src.
  • End to end on the devbox as above (172 s to 22 s).

Size

About 20 changed lines; it stands alone because it is one new option and one caller.

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at ea5ec77a. Requesting changes for one regression.

Blocker: a --timeout over 170 s now outlives the CDP protocol timeout. snapshot launches Chrome through launchManagedBrowser with no protocolTimeout, so puppeteer's 180 s default applies. SEEK_SETTLES_BEFORE_PROTOCOL_TIMEOUT_MS (170 s) exists to keep the in-page settle wait under that limit, so a stuck seek ends with SeekNotSettledError ... still waiting on hf-seek. This PR passes opts.timeout through with no upper bound. A caller who does what the render-ready error tells them to ("raise --timeout if it loads slowly"), e.g. --timeout 5m, and then hits a stuck seek gets a raw Runtime.callFunctionOn timed out protocol error at 180 s. Before this PR they got the named error at 170 s. That loses the "names what it was waiting on" behaviour this PR promises.

Fix (snapshot.ts):

seekSettleTimeoutMs: Math.min(opts.timeout ?? RENDER_READY_TIMEOUT_MS, SEEK_SETTLES_BEFORE_PROTOCOL_TIMEOUT_MS),

Please also add a test that pins the clamp.

Non-blocking: the --timeout help text still says only "Ms to wait for the composition to become render-ready". It now also limits each still's seek, so the help text should say so.

Verified:

  • captureCompositionFrame.test.ts passes 34/34 at this head.
  • With captureCompositionFrame.ts reverted to main, exactly "lets a caller bound how long a seek may stay unsettled" fails. That matches the fails without the fix: line.
  • check, compare and layout keep the 170 s default.

@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 271 (base branch 271), smooth 121 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (0)

@miguel-heygen

Copy link
Copy Markdown
Collaborator Author

Fixed: the clamp lives in settleCompositionSeek itself (the owner of the 170 s protocol margin), so every caller is covered, not only snapshot; new test pins it (red when the clamp is removed) and the --timeout help now says it also bounds each still's seek, up to 170 s.

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed at c4980cd9. Approving.

  • The clamp lives in settleCompositionSeek as Math.min(seekSettleTimeoutMs ?? 170 s, 170 s). A --timeout over 170 s now ends in the named SeekNotSettledError before the 180 s CDP timeout, and every other caller keeps the 170 s default.
  • The --timeout help text now says it also limits each still's seek, up to 170 s.
  • captureCompositionFrame.test.ts passes 35/35. With the clamp removed (previous head's captureCompositionFrame.ts), "never lets a seek stay unsettled past the protocol timeout" fails. As verified at the previous head, the original test fails without the option. Both tests match the fails without the fix: line.
  • CI at this head: CI, Comments, regression, preview-regression, Player perf and PR captures had passed; one CI run, CodeQL and Windows render verification were still running.

@miguel-heygen
miguel-heygen added this pull request to the merge queue Nov 1, 2026
Merged via the queue into main with commit 52a4298 Nov 1, 2026
130 of 131 checks passed
@miguel-heygen
miguel-heygen deleted the fix/snapshot-media-prep-hang branch November 1, 2026 03:02
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