yewstack/yew · error
To suspend rendering, a <Suspense /> component is required.
Error message
To suspend rendering, a <Suspense /> component is required.
What it means
When a component's render yields a suspension (use_prepared_state, use_transitive_state, or anything returning SuspensionResult), Yew walks up the scope tree via find_parent_scope::<BaseSuspense>() to register the suspension with the nearest Suspense boundary. This expect fires when no <Suspense> component exists above the suspending component: suspending is only legal inside a boundary that can display a fallback while the component waits.
Source
Thrown at packages/yew/src/html/component/lifecycle.rs:461
fn suspend(&mut self, shared_state: &Shared<Option<ComponentState>>, suspension: Suspension) {
// Currently suspended, we re-use previous root node and send
// suspension to parent element.
if suspension.resumed() {
// schedule a render immediately if suspension is resumed.
scheduler::push_component_render(
self.comp_id,
Box::new(RenderRunner {
state: shared_state.clone(),
}),
);
} else {
// We schedule a render after current suspension is resumed.
let comp_scope = self.inner.any_scope();
let suspense_scope = comp_scope
.find_parent_scope::<BaseSuspense>()
.expect("To suspend rendering, a <Suspense /> component is required.");
let comp_id = self.comp_id;
let shared_state = shared_state.clone();
suspension.listen(Callback::from(move |_| {
scheduler::push_component_render(
comp_id,
Box::new(RenderRunner {
state: shared_state.clone(),
}),
);
scheduler::start();
}));
if let Some(ref last_suspension) = self.suspension {
if &suspension != last_suspension {
// We remove previous suspension from the suspense.
BaseSuspense::resume(&suspense_scope, last_suspension.clone());
}View on GitHub (pinned to 0e4a05472f)
Solutions
- Wrap the suspending component (usually the page/route component) in <Suspense fallback={...}>
- Ensure the boundary exists from the very first render, not added in a later pass
- If no fallback UI is wanted, replace the suspense-based hook with plain use_state plus an effect-driven fetch
- Check every consumer of the hook, including components rendered through routers or portals
Example fix
// before: use_prepared_state inside UserProfile, no boundary above it
html! { <UserProfile /> }
// after
html! {
<Suspense fallback={html! { <p>{ "Loading..." }</p> }}>
<UserProfile />
</Suspense>
} Defensive patterns
Strategy: validation
Prevention
- Treat any suspense-returning hook as requiring a <Suspense> ancestor - wrap page components by default
- Mount the boundary on the first render; never add it conditionally later
- When adding use_prepared_state to an existing component, immediately check its ancestors for a boundary
When it happens
Trigger: A component calling use_prepared_state/use_transitive_state (or otherwise producing Err(Suspension) from render) that is mounted without a <Suspense> ancestor - e.g. directly at the app root, on a router page that forgot the boundary, or where the Suspense is behind a flag that is false on the first render.
Common situations: Adding a data-fetching suspense hook during CSR-only development where no boundary was ever needed; restructuring the tree so the boundary ends up below the suspending component; conditionally rendering the <Suspense> itself.
Related errors
- failed to deserialize state
- a resuming component must have a Suspense ancestor
- failed to create detached element
- failed to clone node.
- failed to remove child element
AI-assisted analysis of yewstack/yew@0e4a05472f (2026-08-22).
Data as JSON: /api/errors/c5528f7cee49ef49.
Report an issue: GitHub.