yewstack/yew · error · syn::Error

missing `type Context`

Error message

missing `type Context`

What it means

`#[linked_state]` requires the annotated `impl LinkedState for T` block to declare `type Context`, `type Input`, optional `type Error`, and `async fn resolve` (lib.rs:65-79). When the item walk finishes without finding an associated type named `Context`, the macro emits this error at the call site (lib.rs:83-84). `Context` becomes the `LinkedStateResolve::Context` dependency (e.g. a DB pool) injected into `resolve` on the server, so the codegen cannot proceed without it.

Source

Thrown at packages/yew-link-macro/src/lib.rs:84

        match item {
            ImplItem::Type(t) if t.ident == "Input" => input_ty = Some(&t.ty),
            ImplItem::Type(t) if t.ident == "Context" => context_ty = Some(&t.ty),
            ImplItem::Type(t) if t.ident == "Error" => error_ty = Some(&t.ty),
            ImplItem::Fn(f) if f.sig.ident == "resolve" => resolve_fn = Some(f),
            other => {
                return Err(syn::Error::new_spanned(
                    other,
                    "#[linked_state] expects only `type Input`, `type Context`, `type Error` \
                     (optional), and `async fn resolve`",
                ));
            }
        }
    }

    let input_ty =
        input_ty.ok_or_else(|| syn::Error::new(Span::call_site(), "missing `type Input`"))?;
    let context_ty =
        context_ty.ok_or_else(|| syn::Error::new(Span::call_site(), "missing `type Context`"))?;
    let resolve_fn = resolve_fn
        .ok_or_else(|| syn::Error::new(Span::call_site(), "missing `async fn resolve`"))?;

    if resolve_fn.sig.asyncness.is_none() {
        return Err(syn::Error::new_spanned(
            resolve_fn.sig.fn_token,
            "`resolve` must be an async fn",
        ));
    }

    let params: Vec<_> = resolve_fn.sig.inputs.iter().collect();
    if params.len() != 2 {
        return Err(syn::Error::new_spanned(
            &resolve_fn.sig.inputs,
            "`resolve` must take exactly two parameters: context and input references",
        ));
    }

View on GitHub (pinned to 0e4a05472f)

Solutions

  1. Add `type Context = YourDep;` naming the type `resolve`'s first parameter receives
  2. If resolve truly needs no context, declare a unit-ish placeholder type (e.g. `type Context = ();`) and accept `_: &()`
  3. Follow the documented skeleton exactly — Context, Input, optional Error, then the async fn

Example fix

// before
#[linked_state]
impl LinkedState for Post {
    type Input = u32;

    async fn resolve(ctx: &DbPool, id: &u32) -> Self {
        ctx.get_post(*id).await
    }
}

// after
#[linked_state]
impl LinkedState for Post {
    type Context = DbPool;
    type Input = u32;

    async fn resolve(ctx: &DbPool, id: &u32) -> Self {
        ctx.get_post(*id).await
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: the impl block must contain `type Context` before adding the attribute
// fn has_context_item(imp: &syn::ItemImpl) -> bool {
//     imp.items.iter().any(|i| matches!(i, syn::ImplItem::Type(t) if t.ident == "Context"))
// }

Prevention

When it happens

Trigger: An impl block under `#[linked_state]` that has `type Input` and `async fn resolve` but no `type Context = DbPool;` line. A differently named type would be rejected earlier by the 'expects only …' check, so this fires only when `Context` is absent.

Common situations: Writing a resolver that takes no external dependency and assuming `Context` is optional (only `Error` is), or trimming boilerplate from a doc example when copying it in.

Related errors


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