yewstack/yew · error · syn::Error

only named fields are supported

Error message

only named fields are supported

What it means

Inside #[derive(Routable)] the variant scanner (packages/yew-router-macro/src/routable_derive.rs:78) rejects tuple variants (Fields::Unnamed) with 'only named fields are supported'. Route parameters captured by a pattern like #[at("/posts/{id}")] are bound by name, so variant payloads must use named fields; unit variants are allowed for parameterless routes.

Source

Thrown at packages/yew-router-macro/src/routable_derive.rs:78

            ident,
            variants: data.variants,
            ats,
            not_found_route,
        })
    }
}

fn parse_variants_attributes(
    variants: &Punctuated<Variant, syn::token::Comma>,
) -> syn::Result<(Option<Ident>, Vec<LitStr>)> {
    let mut not_founds = vec![];
    let mut ats: Vec<LitStr> = vec![];

    let mut not_found_attrs = vec![];

    for variant in variants.iter() {
        if let Fields::Unnamed(ref field) = variant.fields {
            return Err(syn::Error::new(
                field.span(),
                "only named fields are supported",
            ));
        }

        let attrs = &variant.attrs;
        let at_attrs = attrs
            .iter()
            .filter(|attr| attr.path().is_ident(AT_ATTR_IDENT))
            .collect::<Vec<_>>();

        let attr = match at_attrs.len() {
            1 => *at_attrs.first().unwrap(),
            0 => {
                return Err(syn::Error::new(
                    variant.span(),
                    format!("{AT_ATTR_IDENT} attribute must be present on every variant"),
                ));

View on GitHub (pinned to 0e4a05472f)

Solutions

  1. Rewrite the variant with named fields matching the route parameter names: Post { id: u32 }
  2. For routes with no parameters use a unit variant (e.g. Home)
  3. Keep field names in sync with the {param} segments in the #[at] pattern, otherwise a separate 'route parameter ... does not have a corresponding field' error follows

Example fix

// before
#[derive(Routable, Clone)]
enum Routes {
    #[at("/posts/{id}")]
    Post(u32),
}

// after
#[derive(Routable, Clone)]
enum Routes {
    #[at("/posts/{id}")]
    Post { id: u32 },
}
Defensive patterns

Strategy: validation

Validate before calling

// parameter-capturing variants must use named fields matching {param} names
// #[at("/posts/{id}")] Post { id: u32 },
// static routes: unit variants  #[at("/")] Home,

Type guard

// route parameters are bound by field name; ensure names line up at compile time
// #[at("/posts/{id}")] Post { id: u32 }  // `{id}` must equal a field ident

Prevention

When it happens

Trigger: Declaring a tuple variant in the route enum, e.g. Post(u32) with #[at("/posts/{id}")] — the fields check fires before the #[at] attribute is even read.

Common situations: Writing concise enum payloads with tuple syntax by habit; converting a data model enum that used tuple variants into the route enum; following non-router enum examples.

Related errors


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