yewstack/yew · error · syn::Error

at attribute must be present on every variant

Error message

at attribute must be present on every variant

What it means

Every variant of a #[derive(Routable)] enum must carry exactly one #[at("...")] attribute so the derive can register it in the generated matchit router (packages/yew-router-macro/src/routable_derive.rs:93). A variant with zero #[at] attributes fails with 'at attribute must be present on every variant'. In this implementation the #[not_found] variant is not exempt — it also needs an #[at] path.

Source

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

    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"),
                ));
            }
            _ => {
                return Err(syn::Error::new_spanned(
                    quote! { #(#at_attrs)* },
                    format!("only one {AT_ATTR_IDENT} attribute must be present"),
                ));
            }
        };

        let lit = attr.parse_args::<LitStr>()?;
        let val = lit.value();

        if val.find('#').is_some() {
            return Err(syn::Error::new_spanned(
                lit,

View on GitHub (pinned to 0e4a05472f)

Solutions

  1. Add exactly one #[at("/path")] to the offending variant — the error span points at the variant itself
  2. For the fallback route keep #[not_found] but also add an #[at("/")] or catch-all-style path as required by this derive
  3. Do not duplicate #[at] on one variant; two or more triggers 'only one at attribute must be present'

Example fix

// before
#[derive(Routable, Clone)]
enum Routes {
    #[at("/")]
    Home,
    #[not_found]
    NotFound,
}

// after
#[derive(Routable, Clone)]
enum Routes {
    #[at("/")]
    Home,
    #[at("/")]
    #[not_found]
    NotFound,
}
Defensive patterns

Strategy: validation

Validate before calling

// every variant (including #[not_found]) needs exactly one #[at("...")]
// enum Routes {
//     #[at("/")] Home,
//     #[at("/")] #[not_found] NotFound,
// }

Prevention

When it happens

Trigger: Adding a new enum variant without an #[at] attribute; marking a fallback variant only with #[not_found] and omitting #[at]; renaming the attribute (e.g. #[route]) or using #[at] without a string literal argument.

Common situations: Extending a route enum during feature work and forgetting the attribute; migrating from an older yew-router where the not-found variant did not need a path; renaming 'at' while refactoring attributes.

Related errors


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