From 9326f93576a952752e71cd0fdb1fdf73bb07fd7c Mon Sep 17 00:00:00 2001 From: Bendik Aagaard Lynghaug Date: Wed, 29 Jul 2026 10:50:02 +0200 Subject: [PATCH] Fix hydration mismatch in CallPanel that crashed room switching The SSR branch rendered an empty call-panel div while the hydrate branch expected a child button node. On any full load/refresh of the lobby room, the mismatched hydration cursor hit tachys's unreachable!() panic path, trapping the wasm instance and killing all reactivity (routing, room switching, SSE) for the rest of the page load, while the already-rendered SSR HTML stayed visually intact. SSR now renders the same default join-button markup hydrate expects. --- src/app.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/app.rs b/src/app.rs index 070fabd..a517be8 100644 --- a/src/app.rs +++ b/src/app.rs @@ -495,10 +495,22 @@ fn CallPanel(room: Memo, me: String) -> impl IntoView { } .into_any() } + // Must mirror the hydrate branch's default (not-in-call) markup exactly - + // hydration reconciles this SSR output against what the hydrate branch + // above expects to find, and an empty div here (vs. the button hydrate + // wants) is a hydration mismatch that panics and traps the whole wasm + // instance, killing all reactivity on the page. #[cfg(not(feature = "hydrate"))] { let _ = (room, me); - view! {
}.into_any() + view! { +
+ +
+ } + .into_any() } }