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

  1. Wrap the prefix in double quotes: `#[scope("/api")]`
  2. Do not use variables, constants, or macros as the argument; it must be a literal string
  3. 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

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


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)