You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[2.0 rc.15 + next] Held navigation never publishes delayed pending feedback #4050
cd report/repros/28-held-navigation-feedback
bun install
bun run repro
The test mounts Feedback in the persistent Router shell, navigates to unresolved lazy route children, waits 400 ms, then releases the route promise. The README also supplies a one-command clean setup and a next-tag switch.
Expected behavior
The status indicator appears beside the old page at the old URL. It remains absent although routing is true and the timer fires. Release commits the new page normally.
Platform
Solid rc.15 and next e371645; Router next.39 / HEAD 4a1685ec8f1a; Bun 1.4.2, system Chrome; development and production.
Additional context
With Router next.30 fixed, Solid rc.13 passes and rc.14 first fails. Compiler rc.13/rc.14 swaps follow the runtime. Router next.39 and built Router HEAD also reproduce. Related #3884 concerns supersession timing rather than this single-navigation feedback failure. Tested hand-rolled transitions without Router pass; the exact runtime trigger remains unisolated.
Findings. This still reproduces on next, with and without the router. It bisects to 1b9ceb6 (#3774), which introduced the L2 hold model.
Cause. It comes from Solid's own context provider, not from the router. On the client, a Provider returns children(() => props.children), which turns all of its children into one memo. When a router shell like [<Feedback/>, props.children] sits under the router's context provider, that memo reads two things: the held route outlet (via matches), and the feedback Show. Under the L2 rules, a memo that reads a held value joins the hold. So the feedback UI stays frozen until the navigation commits, even though its own Show has already recomputed.
At the signals level, createMemo(() => [held(), V()]) with V = createMemo(() => isPending(p) && latest(x)) published on rc.13 and is held now. The result also depends on read order: reading latest(x) directly in the combined memo publishes, but [pending(), latest(x)] is held.
Workaround. Wrap the shell's children in an element, for example <main><Feedback/>{props.children}</main>. Each child then gets its own insert, so they no longer share one memo.
Status. Parked while we decide whether the hold rules or the provider should change. A candidate provider-side fix exists, giving each accessor child its own memo, but it hasn't been merged.
Fixed in #4065 (merged into next). The cause was one level down from the Provider: a memo that reads a verdict memo (isPending/latest) beside a held value joined the hold, so the verdict waited for the landing. The Provider's children(() => props.children) merges the router shell's children into exactly such a memo. Such a memo now shows the verdict immediately, beside the held page, the same way the inline probe or a render effect reading both already did. The workaround (wrapping the shell's children in an element) is no longer needed once this ships.
Activity
ryansolid commentedon Oct 14, 2026
Generated by Claude Code
Merge pull request #4065 from solidjs/fix/held-memo-verdict-memo-u10
ryansolid commentedon Oct 14, 2026
Fixed in #4065 (merged into
next). The cause was one level down from the Provider: a memo that reads a verdict memo (isPending/latest) beside a held value joined the hold, so the verdict waited for the landing. The Provider'schildren(() => props.children)merges the router shell's children into exactly such a memo. Such a memo now shows the verdict immediately, beside the held page, the same way the inline probe or a render effect reading both already did. The workaround (wrapping the shell's children in an element) is no longer needed once this ships.Generated by Claude Code
fix(signals): a memo over a verdict memo shows the verdict beside a h…
fix(signals): a derived store over latest() never serves its seed aft…
fix(signals): an async memo over a verdict memo asks each question on…
fix(signals): latest() of a memo born in a lane throws NotReady, not …
fix(signals): latest() opens no transaction for its verdict; its read…
fix(signals): a memo over a re-asked async memo is born held with the…
fix(signals): a memo waiting on a held flight is the hold's work at i…
probe(signals): #4544 probed-held bit — a probe of an unheld node ear…
fix(signals): seat a verdict reader per hold — the posture is release…
test(signals): shadow the per-hold seat table against the engine
fix(signals): seat a verdict reader per hold — the posture is release…