Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[GUI] Firefox: route-change view transition deadlocks ~5s (update callback waits on rAF the pending transition holds)

Open Beginner friendly
#3,673 2 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 3 days

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
76/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
frontend

Research direction

Start with apps/host/src/lib/router.ts and inspect navigateHash() and its document.startViewTransition() update callback. The issue reports a Firefox stall caused by waiting for two animation frames and describes a timeout fallback that was verified locally. Confirm the route transition behavior in Firefox after applying the reported change; the work is done when navigation responds immediately without breaking the crossfade.

Written by the indexing model from the issue text.

Description

Problem: Any route change in the App Host UI (sidebar engine chip, New conversation) makes the page swallow all clicks for ~4-5 s in Firefox, then it recovers by itself. The page is not frozen; a reload is not needed.

Environment: Strata image 0.2.0-beta-nvfp4.3.1 (strata-nvfp4 fork build; apps/host/src/lib/router.ts identical to upstream), Firefox 158.0.1, Fedora Linux, RTX 5090 32 GB, model qwen3.8-flash-next NVFP4, App Host via Caddy on LAN.

Reproduce: Firefox, open the App Host UI, click the engine chip at the sidebar foot (or New conversation). Expected: view crossfades to the target route immediately. Actual: no click anywhere registers for ~4-5 s; CSS animations keep pulsing; the Monitor view's 5 s auto-refresh shows no update until the stall passes; then everything works again. Deterministic on every attempt.

Mechanism: navigateHash() starts a same-document document.startViewTransition() whose update callback flips the hash synchronously, then resolves after two requestAnimationFrame()s:

const transition = document.startViewTransition(
  () => new Promise(done => {
    window.location.hash = next;
    requestAnimationFrame(() => requestAnimationFrame(() => done()));
  }),
);

While a pending view transition waits on its update callback, the browser holds the rendering pipeline - and rAF callbacks are rendering-driven. On Firefox this deadlocks until an internal update-pending guard (observed ~4-5 s) forces it through. That single deadlock explains every symptom: the hash already equals the target, so if (window.location.hash === next) return; early-returns on every further navigation click; non-nav clicks land on a paint-held document; timer-driven DOM updates (Monitor refresh) are deferred; and the main thread is idle throughout, so the DevTools console is instant.

Evidence (collected live during stalls, Firefox DevTools):

  • performance.getEntriesByType('resource') right after recovery: no entry > 300 ms (nothing network-bound).
  • No long tasks anywhere; console evaluation instant (main thread idle).
  • DOM probe (elementFromPoint, computed pointer-events, [inert]) identical frozen vs. healthy - no input interceptor.
  • Stall is consistent 4-5 s on every click; setting document.documentElement.dataset.motion = 'reduced' (which takes the existing non-morph path in navigateHash) removes it immediately.
  • Chromium never reproduces it, and hidden/background tabs skip view transitions entirely, so headless UI tests structurally cannot catch this.

Note: isWebKitGtk() exists because WebKitGTK crashes on startViewTransition - same API, same engine-quirk category, different failure mode. Firefox's implementation doesn't crash; it starves the callback.

Proposed fix (either suffices):

  1. Race the frame wait against a deadline, one line:
() => new Promise(done => {
  window.location.hash = next;
  requestAnimationFrame(() => requestAnimationFrame(done));
  setTimeout(done, 250); // safety rail: rAF can be held by the transition itself
})

(Double resolution is a no-op; unaffected engines behave exactly as before. We have shipped this local edit over the built bundle and the stall is gone in Firefox 158.)

  1. Or gate Firefox the way WebKitGTK is gated, though that drops the crossfade for all Firefox users.

Reproduction status: reproduced locally (two users, every attempt, workaround and fix both verified).

Dominant language
C++
Stars
11.6k
Forks
1k
PR merge metrics
No merged PRs in 30d

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Niko1221/Strata

All issues in Niko1221/Strata

Similar issues

More C++ issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.