yewstack/yew · error · syn::Error
missing `type Input`
Error message
missing `type Input`
What it means
`#[linked_state]` (packages/yew-link-macro) rewrites an `impl LinkedState for T` block into the framework's `LinkedState`/`LinkedStateResolve` impls. It walks the impl items collecting `type Input`, `type Context`, optional `type Error`, and `async fn resolve`; after the walk (lib.rs:81-82), a missing `type Input` produces this `syn::Error` at the macro call site. `Input` is the argument type the server-side `resolve` receives, so the macro cannot generate code without it.
Source
Thrown at packages/yew-link-macro/src/lib.rs:82
for item in &impl_block.items {
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
- Add `type Input = u32;` (or your id type) to the impl block, matching what `resolve`'s second parameter accepts
- Copy the full skeleton from the macro's doc comment: `type Context`, `type Input`, then `async fn resolve(&Ctx, &Input) -> Self`
- Keep only the four allowed items — any other item is rejected with its own error
Example fix
// before
#[linked_state]
impl LinkedState for Post {
type Context = DbPool;
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 Input` before adding the attribute
// fn has_input_item(imp: &syn::ItemImpl) -> bool {
// imp.items.iter().any(|i| matches!(i, syn::ImplItem::Type(t) if t.ident == "Input"))
// } Prevention
- Start every `#[linked_state]` impl from the documented skeleton: `type Context`, `type Input`, optional `type Error`, `async fn resolve` — nothing else
- Keep `type Input` aligned with the second parameter type of `resolve` so the macro's later arity/type checks pass too
- Run `cargo check` on the package immediately after adding the attribute; all missing-item errors point at the macro invocation
When it happens
Trigger: An impl block annotated with `#[linked_state]` that declares `type Context` and `async fn resolve` but contains no `type Input = …;` item. (Writing a differently named associated type instead hits the 'expects only …' error earlier, so this message means `Input` is simply absent.)
Common situations: First use of the linked-state API where the boilerplate `type Input` line was trimmed from the example, or refactoring the impl and deleting what looked like an unused associated type.
Related errors
- missing `type Context`
- missing `async fn resolve`
- only structs are supported
- this hook takes 2 arguments but 1 argument was supplied
- this hook takes 2 arguments but 1 argument was supplied
AI-assisted analysis of yewstack/yew@0e4a05472f (2026-08-22).
Data as JSON: /api/errors/a05a3bec2b7a3332.
Report an issue: GitHub.