{"record":{"id":"c42410fb7e27174e","repo":"actix/actix-web","slug":"scope-macro-must-be-attached-to-a-module","errorCode":null,"errorMessage":"#[scope] macro must be attached to a module","messagePattern":"#\\[scope\\] macro must be attached to a module","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"actix-web-codegen/src/scope.rs","lineNumber":45,"sourceCode":"            err.span(),\n            \"argument to scope macro is not a string literal, expected: #[scope(\\\"/prefix\\\")]\",\n        )\n    })?;\n\n    let scope_prefix_value = scope_prefix.value();\n\n    if scope_prefix_value.ends_with('/') {\n        // trailing slashes cause non-obvious problems\n        // it's better to point them out to developers rather than\n\n        return Err(syn::Error::new(\n            scope_prefix.span(),\n            \"scopes should not have trailing slashes; see https://docs.rs/actix-web/4/actix_web/struct.Scope.html#avoid-trailing-slashes\",\n        ));\n    }\n\n    let mut module = syn::parse::<syn::ItemMod>(input).map_err(|err| {\n        syn::Error::new(err.span(), \"#[scope] macro must be attached to a module\")\n    })?;\n\n    // modify any routing macros (method or route[s]) attached to\n    // functions by prefixing them with this scope macro's argument\n    if let Some((_, items)) = &mut module.content {\n        for item in items {\n            if let syn::Item::Fn(fun) = item {\n                fun.attrs = fun\n                    .attrs\n                    .iter()\n                    .map(|attr| modify_attribute_with_scope(attr, &scope_prefix_value))\n                    .collect();\n            }\n        }\n    }\n\n    Ok(module.to_token_stream().into())\n}","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/actix/actix-web/blob/4d435abc281842f3cbee165b6cde739e001d3a25/actix-web-codegen/src/scope.rs#L27-L63","documentation":"This compile-time error fires when the `#[scope(\"...\")]` macro is attached to an item that is not a Rust module (`mod`). The macro attempts `syn::parse::<syn::ItemMod>(input)` at line 44 and if the annotated item is a function, struct, impl block, or anything else, parsing fails with this message.","triggerScenarios":"Attaching `#[scope(\"/api\")]` to a function, struct, enum, or impl block instead of a `mod` block. For example, `#[scope(\"/api\")] async fn handler() { ... }` will fail because `scope` expects a module.","commonSituations":"Developers who confuse `#[scope]` (module-level macro) with `web::scope()` (runtime API), or who try to scope a single handler function instead of a group of routes in a module.","solutions":["Move the routes into a module and apply `#[scope]` to the module: `#[scope(\"/api\")] mod api { ... }`","If you need to scope a single handler, use the runtime `web::scope(\"/api\").route(...)` API instead","Ensure the annotated item is declared with `mod`, not `fn`, `struct`, etc."],"exampleFix":"// before\n#[scope(\"/api\")]\nasync fn handler() -> impl Responder { ... }\n\n// after\n#[scope(\"/api\")]\nmod api {\n    use actix_web::*;\n\n    #[get(\"/users\")]\n    pub async fn users() -> impl Responder {\n        HttpResponse::Ok()\n    }\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Compile-time error. #[scope(...)] must be on a module:\n// #[scope(\"/api\")]\n// mod api { ... } — correct\n//\n// #[scope(\"/api\")]\n// fn handler() { ... } — incorrect (must be a module)","tryCatchPattern":null,"preventionTips":["Only attach #[scope(...)] to mod declarations","For scoping individual handlers at runtime, use App::new().service(web::scope(\"/api\").route(...))","Review the actix-web scope module documentation for correct usage patterns"],"tags":["rust","actix-web","codegen","routing","compile-time","macro","scope"],"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"}