yewstack/yew · error

no ctx found

Error message

no ctx found

What it means

This panic is `use_context::<Theme>().expect("no ctx found")` inside `ThemedButtonHOC`, the higher-order component from Yew 0.22's struct-component HOC guide. `use_context` walks the component tree for the nearest ancestor `ContextProvider<Theme>` and returns `Option<Theme>`; None means no provider for that exact type was found above this component. The guide wires the provider in `ThemeContextProvider` via `<ContextProvider<Theme> context={(*ctx).clone()}>`, so the HOC panics whenever it is rendered outside that subtree.

Source

Thrown at website/versioned_docs/version-0.22/advanced-topics/struct-components/hoc.mdx:43

#[component]
pub fn App() -> Html {
    let ctx = use_state(|| Theme {
        foreground: "#000000".to_owned(),
        background: "#eeeeee".to_owned(),
    });

    html! {
        <ContextProvider<Theme> context={(*ctx).clone()}>
            <ThemedButtonHOC />
        </ContextProvider<Theme>>
    }
}

// highlight-start
#[component]
pub fn ThemedButtonHOC() -> Html {
    let theme = use_context::<Theme>().expect("no ctx found");

    html! {<ThemedButtonStructComponent {theme} />}
}
// highlight-end

#[derive(Properties, PartialEq)]
pub struct Props {
    pub theme: Theme,
}

struct ThemedButtonStructComponent;

impl Component for ThemedButtonStructComponent {
    type Message = ();
    type Properties = Props;

    fn create(_ctx: &Context<Self>) -> Self {
        Self

View on GitHub (pinned to 0e4a05472f)

Solutions

  1. Wrap the tree (or at least the route subtree containing the HOC) in `<ContextProvider<Theme> context={theme.clone()}>` — i.e. render via `ThemeContextProvider` as the guide does
  2. Confirm provider and consumer use the identical type `Theme`, not a wrapper or a renamed copy
  3. Replace the expect with a fallback: `use_context::<Theme>().unwrap_or_default()` (impl `Default` for `Theme`) or a `match` with a hard-coded default theme
  4. In tests, mount `ThemedButtonHOC` inside `ThemeContextProvider` rather than standalone

Example fix

// before
pub fn ThemedButtonHOC() -> Html {
    let theme = use_context::<Theme>().expect("no ctx found");
    html! { <ThemedButtonStructComponent {theme} /> }
}

// after — app root provides the context
#[function_component(App)]
fn app() -> Html {
    html! {
        <ContextProvider<Theme> context={Theme::default()}>
            <ThemedButtonHOC />
        </ContextProvider<Theme>>
    }
}
Defensive patterns

Strategy: fallback

Validate before calling

// central accessor: the None case is handled in exactly one place
#[hook]
fn use_theme() -> Theme {
    use_context::<Theme>().unwrap_or_default()
}

// provider wiring check (fails loudly in dev, early)
// render <ThemeContextProvider> above every consumer in the app tree

Prevention

When it happens

Trigger: Mounting `<ThemedButtonHOC/>` without an ancestor `<ContextProvider<Theme>>`; providing a different type than the one consumed (e.g. the provider stores a wrapper struct while the HOC asks for `Theme`); the provider living in a sibling branch of the tree; the provider being unmounted on route change while the HOC stays mounted.

Common situations: Extracting the HOC example into demos or unit tests that forgot to wrap it in `ThemeContextProvider`; refactors that move the provider below the consumer; type renames during version upgrades that silently desynchronize provider and consumer context types.

Related errors


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