leptos-rs/leptos · error
You cannot use Suspend on an attribute outside Suspense
Error message
You cannot use Suspend on an attribute outside Suspense
What it means
An async (Suspend-wrapped) class attribute cannot produce its value synchronously. During server HTML string generation (to_html), the framework calls now_or_never(); if the future is not ready, rendering is outside a Suspense context that would otherwise await it, so it panics.
Source
Thrown at tachys/src/reactive_graph/class.rs:985
impl<Fut> IntoClass for Suspend<Fut>
where
Fut: Clone + Future + Send + 'static,
Fut::Output: IntoClass,
{
type AsyncOutput = Fut::Output;
type State = Rc<RefCell<Option<<Fut::Output as IntoClass>::State>>>;
type Cloneable = Self;
type CloneableOwned = Self;
fn html_len(&self) -> usize {
0
}
fn to_html(self, style: &mut String) {
if let Some(inner) = self.inner.now_or_never() {
inner.to_html(style);
} else {
panic!("You cannot use Suspend on an attribute outside Suspense");
}
}
fn hydrate<const FROM_SERVER: bool>(
self,
el: &crate::renderer::types::Element,
) -> Self::State {
let el = el.to_owned();
let state = Rc::new(RefCell::new(None));
reactive_graph::spawn_local_scoped({
let state = Rc::clone(&state);
async move {
*state.borrow_mut() =
Some(self.inner.await.hydrate::<FROM_SERVER>(&el));
self.subscriber.forward();
}
});
stateView on GitHub (pinned to 32d20f6c9d)
Solutions
- Wrap the containing view in <Suspense> so the async attribute can be awaited during SSR.
- Make the class value synchronous for the initial render (resolve the data before rendering, or use a sync signal).
- If async data is required, move the async read inside a Suspense boundary or use await Suspending() in the component body (leptos).
Example fix
// before
view! { <div class=Suspend(async move { load_class().await }) /> }
// after
view! {
<Suspense fallback=|| ()>
<div class=Suspend(async move { load_class().await }) />
</Suspense>
} Defensive patterns
Strategy: validation
Validate before calling
fn ensure_suspense_context(rendering_to_html: bool, inside_suspense: bool) { if rendering_to_html && !inside_suspense { panic!("async class attribute requires a Suspense boundary"); } } Type guard
fn class_is_sync(c: &impl Fn() -> String) {} // prefer sync closures/signals over Suspend for attributes Try / catch
std::panic::catch_unwind(|| view_to_html(&view)).map_err(|_| /* rebuild view inside Suspense */)
Prevention
- Only use Suspend on attributes inside <Suspense>.
- Prefer synchronous signals for class values in initial renders.
- Move async data fetching above the component (resources awaited in Suspense).
- Test SSR output locally to catch this before deploy.
When it happens
Trigger: Using Suspend (async-derived class value) as a class attribute while rendering to HTML (SSR/dry-run) without the attribute being inside a <Suspense> component.
Common situations: Making a class reactive/async in a component rendered during SSR but forgetting to wrap the view in Suspense; refactoring an attribute to an async source without updating the rendering context.
Related errors
- You cannot use Suspend on an attribute outside Suspense
- Reading from a LocalResource outside Suspense in `ssr` mode
- no shared context
- children should not be removed until we render here
- Failed to find the route {path} requested by the user. This
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/45364a84a5ce174f.
Report an issue: GitHub.