yewstack/yew · critical
use_linked_state requires a LinkProvider
Error message
use_linked_state requires a LinkProvider
What it means
use_linked_state<T> (packages/yew-link/src/lib.rs:512) reads LinkContextInner via use_context and panics with .expect when no ancestor rendered <LinkProvider>. The hook needs the provider's cache, endpoint and (on SSR) resolver to fetch or resolve linked state, so a missing provider is always a programming error, not a recoverable condition — the doc comment explicitly states it panics.
Source
Thrown at packages/yew-link/src/lib.rs:512
/// state is fetched from the provider's `endpoint` URL.
///
/// The hook suspends while the state is being resolved/fetched for the first
/// time. On [`refresh`](LinkedStateHandle::refresh), the previous value is
/// kept visible (stale-while-revalidate) and
/// [`is_refreshing`](LinkedStateHandle::is_refreshing) returns `true` until
/// the fresh data arrives.
///
/// Multiple components requesting the same `(T, Input)` concurrently share a
/// single in-flight request.
///
/// # Panics
///
/// Panics if there is no ancestor [`LinkProvider`] in the component tree.
#[hook]
pub fn use_linked_state<T: LinkedState>(input: T::Input) -> SuspensionResult<LinkedStateHandle<T>> {
#[cfg(any(feature = "ssr", target_arch = "wasm32"))]
let link_ctx =
use_context::<LinkContextInner>().expect("use_linked_state requires a LinkProvider");
#[cfg(any(feature = "ssr", target_arch = "wasm32"))]
type Prepared<T, E> = Result<T, LinkError<E>>;
#[cfg(feature = "ssr")]
{
let prepared = {
let link_ctx = link_ctx.clone();
yew::functional::use_prepared_state_with_suspension(
input,
move |input: Rc<T::Input>| {
let link_ctx = link_ctx.clone();
async move { link_ctx.resolve_local::<T>(&input).await }
},
)
}?;
let result: Rc<Prepared<T, T::Error>> =View on GitHub (pinned to 0e4a05472f)
Solutions
- Mount <LinkProvider> above every component that calls use_linked_state — app root is the safest place: html! { <LinkProvider endpoint={AttrValue::from("/api/link")}> <App /> </LinkProvider> }
- In tests, wrap the component under test with a minimal LinkProvider
- On SSR additionally pass a resolver prop (see the resolve_local panic) so the provider is fully configured
Example fix
// before
html! { <ProfilePage /> } // ProfilePage calls use_linked_state
// after
html! {
<LinkProvider endpoint={AttrValue::from("/api/link")}>
<ProfilePage />
</LinkProvider>
} Defensive patterns
Strategy: validation
Validate before calling
// render every use_linked_state consumer inside a LinkProvider
// html! { <LinkProvider endpoint={AttrValue::from("/api/link")}> <App /> </LinkProvider> } Type guard
// debug-only check you can drop into a component before calling the hook
// #[cfg(debug_assertions)]
// if yew::functional::use_context::<crate::LinkContextInner>().is_none() {
// panic!("use_linked_state requires a LinkProvider ancestor");
// } Prevention
- Place LinkProvider at the root layout so all routes inherit it
- When extracting a component into a test or story, wrap it in a minimal LinkProvider
- Treat 'no provider' as a wiring bug, not a runtime condition to recover from
When it happens
Trigger: Calling use_linked_state in a component mounted outside a <LinkProvider> subtree; putting the provider next to instead of above the consuming component; rendering the hook during SSR with no provider at all in the server tree.
Common situations: Adding a linked-state hook to a new page while the provider only wraps other routes; reorganizing the app layout so the root provider is dropped; testing a component in isolation without wrapping it in a provider.
Related errors
- failed to find worker context
- resolver not set on server-side LinkProvider
- unkeyed child in fully keyed list
- invalid attribute key
- could not set property
AI-assisted analysis of yewstack/yew@0e4a05472f (2026-08-22).
Data as JSON: /api/errors/5228ceb8317b95f1.
Report an issue: GitHub.