leptos-rs/leptos · error
internal error: entered unreachable code
Error message
internal error: entered unreachable code
What it means
During `hydrate_async` of a reactive view fragment, tachys builds a `RenderEffect::new_with_async_value` whose closure asserts `prev` is `Some` (the previously rendered sub-view state used by `value.rebuild`). The panic means the effect closure ran while the async initial value had not resolved (slot still `None`) or after the value was taken — the reactive fragment re-rendered before its seed state existed.
Source
Thrown at tachys/src/reactive_graph/mod.rs:276
{
let mut fun = fun.clone();
move |prev| {
/// codegen optimisation:
fn get_guard(
hook: &Option<Arc<dyn throw_error::ErrorHook>>,
) -> Option<throw_error::ResetErrorHookOnDrop>
{
hook.as_ref()
.map(|h| throw_error::set_error_hook(Arc::clone(h)))
}
let _guard = get_guard(&hook);
let value = fun.invoke();
if let Some(mut state) = prev {
value.rebuild(&mut state);
state
} else {
unreachable!()
}
}
},
async move { fun.invoke().hydrate_async(&cursor, &position).await },
)
.await
.into()
}
fn into_owned(self) -> Self::Owned {
self
}
}
impl<F, V> AddAnyAttr for F
where
F: ReactiveFunction<Output = V>,
V: RenderHtml + 'static,View on GitHub (pinned to 32d20f6c9d)
Solutions
- Delay signal updates until after async hydration completes (e.g. run updates in an effect spawned after `hydrate` returns, or gate the signal source on a `hydrated` flag).
- Avoid rapid branch swaps (`Show`/`Either`) around async-hydrated reactive fragments during initial load.
- Upgrade leptos/tachys — later releases addressed `new_with_async_value` prev-value races.
- Reproduce minimally and report to the Leptos tracker if stock components trigger it.
Example fix
// before: signal updated during hydration
create_effect(move |_| { data.update(...); }); // may run pre-hydration
// after: gate until hydrated
let hydrated = RwSignal::new(false);
create_effect(move |_| { if hydrated.get() { data.update(...); } });
// set hydrated = true after view hydrates/mounts Defensive patterns
Strategy: fallback
Validate before calling
// Block reactive fragment updates until async hydration completes
let hydrated = RwSignal::new(false);
// after hydrate_async resolves in your bootstrap:
hydrated.set(true);
create_effect(move |_| {
if !hydrated.get() { return; }
let _ = reactive_fragment_signal.get();
}); Type guard
fn fragment_state_ready(prev: &Option<FragmentState>) -> bool { prev.is_some() } Try / catch
// Wrap hydration bootstrap with catch_unwind + fallback
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
futures::executor::block_on(view.hydrate_async(...))
}));
if result.is_err() { render_client_fallback(); } Prevention
- Never write signals bound to a Suspense fragment before it resolves
- Queue post-hydration updates via queue_microtask after mount returns
- Avoid router navigation racing initial async hydration
- Test SSR+hydration flows with signals that fire during load
When it happens
Trigger: A reactive function inside a `<Suspense>`/async-hydrated fragment updates (signal fires) before `hydrate_async`'s future resolves and stores the initial view state; or the fragment is rebuilt/reset while the async value is pending.
Common situations: SSR + async hydration where a global signal changes during initial load (e.g. router navigation, websocket push) before hydration completes; Suspense fallback swapping in the resolved branch and immediately re-running the effect.
Related errors
- internal error: entered unreachable code
- internal error: entered unreachable code
- internal error: entered unreachable code
- Reading from a LocalResource outside Suspense in `ssr` mode
- {location:?} expected context of type {type_name:?} to be pr
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/f2b1c3dce8f2c08d.
Report an issue: GitHub.