actix/actix-web · error · syn::Error
#[scope] macro must be attached to a module
Error message
#[scope] macro must be attached to a module
What it means
`#[scope]` is designed to prefix routes defined inside a module. At actix-web-codegen/src/scope.rs:44-46 the macro parses the item as `syn::ItemMod`; if it isn't a module the parse error is replaced with this clear message.
Source
Thrown at actix-web-codegen/src/scope.rs:45
err.span(),
"argument to scope macro is not a string literal, expected: #[scope(\"/prefix\")]",
)
})?;
let scope_prefix_value = scope_prefix.value();
if scope_prefix_value.ends_with('/') {
// trailing slashes cause non-obvious problems
// it's better to point them out to developers rather than
return Err(syn::Error::new(
scope_prefix.span(),
"scopes should not have trailing slashes; see https://docs.rs/actix-web/4/actix_web/struct.Scope.html#avoid-trailing-slashes",
));
}
let mut module = syn::parse::<syn::ItemMod>(input).map_err(|err| {
syn::Error::new(err.span(), "#[scope] macro must be attached to a module")
})?;
// modify any routing macros (method or route[s]) attached to
// functions by prefixing them with this scope macro's argument
if let Some((_, items)) = &mut module.content {
for item in items {
if let syn::Item::Fn(fun) = item {
fun.attrs = fun
.attrs
.iter()
.map(|attr| modify_attribute_with_scope(attr, &scope_prefix_value))
.collect();
}
}
}
Ok(module.to_token_stream().into())
}View on GitHub (pinned to 937960ca67)
Solutions
- Move the annotated routes into a module and put `#[scope(...)]` on the `mod`.
- If you want runtime prefixing for a single route, use `web::scope("/api").route(...)` in your `App` setup instead of the macro.
Example fix
// before
#[scope("/api")]
async fn handler() -> HttpResponse { ... }
// after
#[scope("/api")]
mod api {
use super::*;
#[get("/users")]
pub async fn users() -> HttpResponse { ... }
} Defensive patterns
Strategy: validation
Validate before calling
// Compile-time only. #[scope(...)] must decorate a `mod` item.
// If you need runtime prefixing of a single handler, use:
// web::scope("/api").route("/x", web::get().to(handler))
// in your App configuration instead. Prevention
- Reserve #[scope] for modules containing multiple route handlers.
- Use the runtime Scope builder for ad-hoc single-route prefixes.
When it happens
Trigger: Placing `#[scope("/api")]` on a function, struct, or `impl` block instead of a `mod`.
Common situations: Expecting `scope` to work like the runtime `Scope::new()` builder on a single handler, rather than as a module-level macro.
Related errors
- invalid service definition, expected #[<method>("<path>")]
- Multiple paths specified! There should be only one.
- The #[route(..)] macro requires at least one `method` attrib
- The #[routes] macro requires at least one `#[<method>(..)]`
- missing arguments for scope macro, expected: #[scope("/prefi
AI-assisted analysis of actix/actix-web@937960ca67 (2026-08-06).
Data as JSON: /data/errors/c42410fb7e27174e.json.
Report an issue: GitHub.