{"record":{"id":"ac03d9ff8296fe2f","repo":"actix/actix-web","slug":"the-routes-macro-requires-at-least-one-meth","errorCode":null,"errorMessage":"The #[routes] macro requires at least one `#[<method>(..)]` attribute.","messagePattern":"The #\\[routes\\] macro requires at least one `#\\[<method>\\(\\.\\.\\)\\]` attribute\\.","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"actix-web-codegen/src/route.rs","lineNumber":536,"sourceCode":"    for attr in std::mem::take(&mut ast.attrs) {\n        match MethodType::from_path(attr.path()) {\n            Ok(method) => methods.push((method, attr)),\n            Err(_) => ast.attrs.push(attr),\n        }\n    }\n\n    let methods = match methods\n        .into_iter()\n        .map(|(method, attr)| {\n            attr.parse_args()\n                .and_then(|args| Args::new(args, Some(method)))\n        })\n        .collect::<Result<Vec<_>, _>>()\n    {\n        Ok(methods) if methods.is_empty() => {\n            return input_and_compile_error(\n                input,\n                syn::Error::new(\n                    Span::call_site(),\n                    \"The #[routes] macro requires at least one `#[<method>(..)]` attribute.\",\n                ),\n            )\n        }\n        Ok(methods) => methods,\n        Err(err) => return input_and_compile_error(input, err),\n    };\n\n    match Route::multiple(methods, ast) {\n        Ok(route) => route.into_token_stream().into(),\n        // on macro related error, make IDEs happy; see fn docs\n        Err(err) => input_and_compile_error(input, err),\n    }\n}\n","sourceCodeStart":518,"sourceCodeEnd":552,"githubUrl":"https://github.com/actix/actix-web/blob/4d435abc281842f3cbee165b6cde739e001d3a25/actix-web-codegen/src/route.rs#L518-L552","documentation":"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.","triggerScenarios":"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(...)]`.","commonSituations":"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).","solutions":["Add at least one HTTP method attribute below `#[routes]`: `#[get(\"/path\")]`, `#[post(\"/path\")]`, etc.","If the function only needs one route, remove `#[routes]` and use a single method attribute directly","Check for typos in method attribute names; they must be lowercase: `get`, `post`, `put`, `delete`, etc."],"exampleFix":"// before\n#[routes]\nasync fn handler() -> impl Responder { ... }\n\n// after\n#[routes]\n#[get(\"/items\")]\n#[post(\"/items\")]\nasync fn handler() -> impl Responder { ... }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Compile-time error. #[routes] requires at least one method attribute:\n// #[routes]\n// #[get(\"/items\")] — must have this or another method attribute\n// async fn handler() { ... }","tryCatchPattern":null,"preventionTips":["Always add at least one #[get(...)], #[post(...)], etc. attribute under #[routes]","Use lowercase method names (get, post, put, delete, patch, head, options, trace, connect)","If only one route is needed, skip #[routes] and use a single method attribute directly"],"tags":["rust","actix-web","codegen","routing","compile-time","macro"],"backgroundTag":null,"analyzedSha":"4d435abc281842f3cbee165b6cde739e001d3a25","analyzedAt":"2026-08-09T01:01:40.926Z","contentChangedAt":"2026-08-09T01:01:40.926Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}