Repository navigation
fix(studio-server): a refused preview frame says so at once instead of timing out - #6074
Open
miguel-heygen wants to merge 2 commits into
Open
miguel-heygen wants to merge 2 commits into
miguel-heygen wants to merge 2 commits into
Conversation
…f timing out A frame the server refuses (project gone, bad variables) loaded a JSON body: no runtime and no error, so Studio waited three 15s budgets and reported 'waiting for runtime'. The refusal now reaches the frame as a page that reports it, like a failing preview script.
Contributor
Edit accuracy: accurate 271 (base branch 271), smooth 154 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (1)
|
terencechotai2-commits
approved these changes
Oct 22, 2026
There was a problem hiding this comment.
Approving at 3f02569d. I found no blocker.
Checked
- Order.
answerRefusedFrameWithPageis registered beforeanswerProjectDirMissingAfterErrorHandlers, so it runs outermost. It rewrites the answer after the folder-gone replacement and afteronError. - Reach. It applies only to
/projects/:id/previewand the paths under it, and only whenSec-Fetch-Dest: iframeand the status is 400 or above. A runtimefetchor an<img>asset request under the same path keeps its JSON. - The player's side. The page seeds
window.__hfPreviewErrors, the same keyEARLY_ERRORS_SCRIPTsets on a served preview.CompositionProbereads it throughfirstAuthorErrorbefore it checks for a runtime, so the shadow fails on the first probe. Studio'suseConsoleErrorCapturereads the same list. - Injection. The only variable in the page is the numeric status, put in through
JSON.stringify, so nothing a request controls reaches the script or the<p>. - Headers. The original headers are copied,
content-typeis set to HTML, andcontent-lengthis dropped for the new body. Neither studio-server nor the CLI server sets a CSP that would block the inline script.
Probes I ran (temporary test file, since removed). Each one was an iframe request through createStudioApi:
- A resolved project whose folder is gone: 404 page, on the preview and on a sub-composition.
?variables=that isn't valid JSON: 400 page.- An unknown project's asset path: 404 page.
- An asset path in the folder-gone project as
Sec-Fetch-Dest: image: still 404 JSON,{"error":"not found","why":"project_dir_missing"}.
CI. Every check on this head passed or was skipped, including the 11 required ones: Windows tests and render, all five edit accuracy shards and their gate, captures, typecheck and build.
Run locally
vitest run src/routes/previewErrorDocument.test.ts src/routes/preview.test.tsin studio-server: 117/117.- Mutant: without the two
api.uselines, the two frame tests fail and the JSON test passes.
Non-blocking
- The reason is dropped. The page says only "HTTP 404" or "HTTP 400". The JSON it replaces can say why, for example
why: "project_dir_missing"for a folder that's gone. Carrying that reason into the message would let Studio say "the project folder is gone" rather than give a bare status.
— tai2
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
When the preview server refuses a frame's request (the project folder is gone, or
?variables=is invalid), the frame now gets a small page that reports the refusal, instead of a JSON body.Why
The shadow reload waits on the new document's runtime. A refused frame loads a JSON body, which has no runtime and raises no error, so nothing tells the player to give up: Studio waits all three 15 s budgets and then reports "The preview did not reload (it took too long to load). It was still waiting for the page and its runtime to load." The old preview stays on screen and edit thumbnails stay held for the whole wait.
Reproduced in Chromium with the built player (
no-load-timeout, as the shadow uses it): a JSON 404 gives noerrorevent and no__playerfor 20 s.Related work
Refs the "preview reload timed out, waiting for runtime" reports. This covers the refused-frame cause only. A page whose own parser-blocking scripts or stylesheets stall also never boots a runtime (reproduced in the same harness); that is a separate cause and is not changed here.
How
createStudioApigets one outer middleware on/projects/:id/previewand/preview/*: when the browser marks the request as a frame navigation (Sec-Fetch-Dest: iframe) and the answer is an error, the body becomes a page that seedswindow.__hfPreviewErrors. The player's composition probe already reads that list, so it raises itserrorevent and the shadow fails at once with the status named. Requests that are not frame navigations keep their JSON.Test plan
previewErrorDocument.test.ts(frame request gets the page, sub-composition frame gets it, plain fetch keeps its JSON). The two frame tests fail without the middleware.createStudioApibehind Chromium with the built player: the error event arrives after about 0.5 s with "The preview page could not be loaded (HTTP 404)."; before, it never arrived.studio-serverpreview and path-safety suites (171 tests),tsc, oxlint, oxfmt and fallow audit pass on the devbox.