actix/actix-web · error · syn::Error
argument to scope macro is not a string literal, expected…
Error message
argument to scope macro is not a string literal, expected: #[scope("/prefix")] What it means
This compile-time error fires when the argument to `#[scope(...)]` cannot be parsed as a Rust string literal (`syn::LitStr`). The macro attempts `syn::parse::<syn::LitStr>(args)` at line 25 and if it fails (e.g., the argument is a number, identifier, or expression), this error is returned.
Solutions
- Wrap the prefix in double quotes: `#[scope("/api")]`
- Do not use variables, constants, or macros as the argument; it must be a literal string
- Check for accidental removal of quotes during refactoring
Example fix
// before
#[scope(/api)]
mod api { ... }
// after
#[scope("/api")]
mod api { ... } Defensive patterns
Strategy: type-guard
Type guard
// Compile-time error. The argument must be a string literal:
// #[scope("/api")] — correct
// #[scope(/api)] — incorrect (bare path)
// #[scope(api)] — incorrect (identifier)
// #[scope(42)] — incorrect (number) Prevention
- Always wrap the scope prefix in double quotes
- Do not use variables or constants as scope prefix arguments
- Use rust-analyzer or an IDE for real-time syntax feedback
When it happens
Trigger: Writing `#[scope(/api)]` (bare path without quotes), `#[scope(42)]` (number), or `#[scope(api)]` (identifier). The argument must be a double-quoted string literal.
Common situations: Forgetting to quote the prefix string, or trying to use a constant or expression as the scope prefix.
Related errors
- missing arguments for scope macro, expected…
- #[scope] macro must be attached to a module
- scopes should not have trailing slashes; see…
- invalid service definition, expected #
- Multiple paths specified! There should be only one.
AI-assisted analysis of actix/actix-web@4d435abc28 (2026-08-09).
Data as JSON: /api/errors/6b963d3448fd9c75.
Report an issue: GitHub.
Appendix: source
Thrown at actix-web-codegen/src/scope.rs:26
};
pub fn with_scope(args: TokenStream, input: TokenStream) -> TokenStream {
match with_scope_inner(args, input.clone()) {
Ok(stream) => stream,
Err(err) => input_and_compile_error(input, err),
}
}
fn with_scope_inner(args: TokenStream, input: TokenStream) -> syn::Result<TokenStream> {
if args.is_empty() {
return Err(syn::Error::new(
Span::call_site(),
"missing arguments for scope macro, expected: #[scope(\"/prefix\")]",
));
}
let scope_prefix = syn::parse::<syn::LitStr>(args.clone()).map_err(|err| {
syn::Error::new(
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| {View on GitHub (pinned to 4d435abc28)