actix/actix-web · error · syn::Error

The #[routes] macro requires at least one `#

Error message

The #[routes] macro requires at least one `#[<method>(..)]` attribute.

What it means

This compile-time error fires when `#[routes]` is applied to a function that has no HTTP method attribute (`#[get(...)]`, `#[post(...)]`, etc.) attached. The `with_methods` function scans all attributes on the function for known method types at line 518-523; if none are found, `methods` is empty and the check at line 533-540 fails.

Solutions

  1. Add at least one HTTP method attribute below `#[routes]`: `#[get("/path")]`, `#[post("/path")]`, etc.
  2. If the function only needs one route, remove `#[routes]` and use a single method attribute directly
  3. Check for typos in method attribute names; they must be lowercase: `get`, `post`, `put`, `delete`, etc.

Example fix

// before
#[routes]
async fn handler() -> impl Responder { ... }

// after
#[routes]
#[get("/items")]
#[post("/items")]
async fn handler() -> impl Responder { ... }
Defensive patterns

Strategy: type-guard

Type guard

// Compile-time error. #[routes] requires at least one method attribute:
// #[routes]
// #[get("/items")] — must have this or another method attribute
// async fn handler() { ... }

Prevention

When it happens

Trigger: Writing `#[routes]` on a function that only has non-routing attributes, or forgetting to add a method attribute below it. For example, `#[routes]` followed by `#[middleware(...)]` but no `#[get(...)]`.

Common situations: Developers who add `#[routes]` first planning to add method attributes later, or who remove the only method attribute without removing `#[routes]`. Also happens when the method attribute name is misspelled (e.g., `#[Get("/")]` with uppercase).

Related errors


AI-assisted analysis of actix/actix-web@4d435abc28 (2026-08-09). Data as JSON: /api/errors/ac03d9ff8296fe2f. Report an issue: GitHub.

Appendix: source

Thrown at actix-web-codegen/src/route.rs:536

    for attr in std::mem::take(&mut ast.attrs) {
        match MethodType::from_path(attr.path()) {
            Ok(method) => methods.push((method, attr)),
            Err(_) => ast.attrs.push(attr),
        }
    }

    let methods = match methods
        .into_iter()
        .map(|(method, attr)| {
            attr.parse_args()
                .and_then(|args| Args::new(args, Some(method)))
        })
        .collect::<Result<Vec<_>, _>>()
    {
        Ok(methods) if methods.is_empty() => {
            return input_and_compile_error(
                input,
                syn::Error::new(
                    Span::call_site(),
                    "The #[routes] macro requires at least one `#[<method>(..)]` attribute.",
                ),
            )
        }
        Ok(methods) => methods,
        Err(err) => return input_and_compile_error(input, err),
    };

    match Route::multiple(methods, ast) {
        Ok(route) => route.into_token_stream().into(),
        // on macro related error, make IDEs happy; see fn docs
        Err(err) => input_and_compile_error(input, err),
    }
}

View on GitHub (pinned to 4d435abc28)