yewstack/yew · error

a resuming component must have a Suspense ancestor

Error message

a resuming component must have a Suspense ancestor

What it means

When a previously suspended component resumes and commits its render, Yew looks up its BaseSuspense ancestor again to hand over the pending rendered callback (BaseSuspense::defer_rendered). This expect fires when that ancestor is gone: the suspension was created under a <Suspense> that has since been unmounted, re-keyed, or re-created while the child was still suspended. It is an internal-consistency panic - the boundary that accepted the suspension is expected to still exist at resume time.

Source

Thrown at packages/yew/src/html/component/lifecycle.rs:523

                let new_node_ref =
                    bundle.reconcile(root, &scope, parent, sibling_slot.to_position(), new_vdom);
                own_slot.reassign(new_node_ref);

                let first_render = !self.has_rendered;
                self.has_rendered = true;

                if resuming_from_suspension {
                    // The DOM we just reconciled still lives in the ancestor
                    // Suspense's detached parent. The Suspense must process
                    // the Resume message and re-render to shift children into
                    // the live tree before our effects observe the DOM.
                    // Hand the pending `rendered` to the Suspense; it will
                    // re-schedule it once it fully un-suspends.
                    let pending = PendingRendered::new(shared_state.clone(), first_render);
                    let suspense_scope = scope
                        .find_parent_scope::<BaseSuspense>()
                        .expect("a resuming component must have a Suspense ancestor");
                    BaseSuspense::defer_rendered(&suspense_scope, self.comp_id, pending);
                } else {
                    scheduler::push_component_rendered(
                        self.comp_id,
                        Box::new(RenderedRunner {
                            state: shared_state.clone(),
                            first_render,
                        }),
                        first_render,
                    );
                }
            }

            #[cfg(feature = "hydration")]
            ComponentRenderState::Hydration {
                ref mut fragment,
                ref parent,
                ref mut own_slot,

View on GitHub (pinned to 0e4a05472f)

Solutions

  1. Hoist the <Suspense> boundary above the conditional or router switch so it stays mounted while any child can suspend
  2. Do not key or conditionally remount the boundary itself
  3. Upgrade to the newest Yew patch release - suspense resume handling has received fixes
  4. If it still reproduces on the latest version, file an issue with a minimal repro (suspension triggered while the boundary unmounts)

Example fix

// before: boundary is swapped out with the route while children still suspend
html! { <Route>{ route_view }</Route> } // <Suspense> lives inside route_view

// after: boundary outlives the switch
html! {
    <Suspense fallback={fallback()}>
        <Route>{ route_view }</Route>
    </Suspense>
}
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Unmounting, re-keying, or conditionally removing the <Suspense> subtree while a child is still suspended (route change mid-load, a toggle flipping the boundary off); re-parenting the suspended component so its scope chain no longer reaches the original boundary.

Common situations: Router-driven page swaps where the boundary lives inside the swapped page; show.then(|| html!{<Suspense>...</Suspense>}) toggled during an async load; upgrading across Yew versions where suspense resume handling had bugs.

Related errors


AI-assisted analysis of yewstack/yew@0e4a05472f (2026-08-22). Data as JSON: /api/errors/907e75e14d55e49e. Report an issue: GitHub.