leptos-rs/leptos · error
Reading from a LocalResource outside Suspense in `ssr` mode
Error message
Reading from a LocalResource outside Suspense in `ssr` mode will cause the response to hang, because LocalResources are always pending on the server.
What it means
In ssr mode a LocalResource never resolves on the server (it is always pending, since its data is client-local). Reading it via into_future outside a Suspense context means there is no LocalResourceNotifier to defer serialization, so leptos panics instead of hanging the HTTP response forever.
Source
Thrown at leptos_server/src/local_resource.rs:147
/// left to handle the `None` and `Err(_)` states.
#[track_caller]
pub fn and_then<U>(&self, f: impl FnOnce(&T) -> U) -> Option<Result<U, E>> {
self.map(|data| data.as_ref().map(f).map_err(|e| e.clone()))
}
}
impl<T> IntoFuture for ArcLocalResource<T>
where
T: Clone + 'static,
{
type Output = T;
type IntoFuture = AsyncDerivedFuture<T>;
fn into_future(self) -> Self::IntoFuture {
if let Some(mut notifier) = use_context::<LocalResourceNotifier>() {
notifier.notify();
} else if cfg!(feature = "ssr") {
panic!(
"Reading from a LocalResource outside Suspense in `ssr` mode \
will cause the response to hang, because LocalResources are \
always pending on the server."
);
}
self.data.into_future()
}
}
impl<T> DefinedAt for ArcLocalResource<T> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
{
NoneView on GitHub (pinned to 32d20f6c9d)
Solutions
- Wrap the reading component/view in <Suspense> so the LocalResource can register its notifier.
- If the data must be available during SSR, use a regular Resource (server-fn backed) instead of LocalResource.
- Only read LocalResources in client/hydration-only code paths.
Example fix
// before
let res = use_local_resource(...);
view! { <p>{move || res.get().map(|d| d.text())}</p> } // panics on ssr
// after
view! {
<Suspense fallback=|| view! { <p>Loading...</p> }>
<p>{move || res.get().map(|d| d.text())}</p>
</Suspense>
} Defensive patterns
Strategy: try-catch
Validate before calling
#[cfg(feature = "ssr")]
fn local_resource_ssr_safe() -> bool {
use leptos::reactive_graph::LocalResourceNotifier;
// true only when rendering inside Suspense (notifier present)
leptos::prelude::use_context::<LocalResourceNotifier>().is_some()
} Try / catch
// Panics cannot be caught idiomatically here; restructure instead. // catch_unwind is a last resort around the whole render: let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| render_app()));
Prevention
- Always read LocalResources inside <Suspense>.
- Use regular Resource for data needed during SSR.
- Review components converted from Resource to LocalResource for SSR reads.
- Run an SSR smoke test (cargo leptos serve + curl) in CI.
When it happens
Trigger: Calling `.get()`/`.await` (into_future) on a LocalResource during SSR when the read happens outside any <Suspense> component, so use_context::<LocalResourceNotifier>() returns None and the ssr feature is enabled.
Common situations: Awaiting a LocalResource in a component rendered on the server without wrapping it in <Suspense>; refactoring a Resource (server-friendly) into a LocalResource (client-only) and forgetting the SSR implications; reading the resource at the top level of a view during server render.
Related errors
- Failed to find the route {path} requested by the user. This
- Unsupported server function HTTP method: {method:?}
- {}
- at {location}, the `sandboxed-arenas` feature is active, but
- You cannot use Suspend on an attribute outside Suspense
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/84b8b29d40f2901e.
Report an issue: GitHub.