{"record":{"id":"b73af54e6da4b828","repo":"actix/actix-web","slug":"scopes-should-not-have-trailing-slashes-see-https","errorCode":null,"errorMessage":"scopes should not have trailing slashes; see https://docs.rs/actix-web/4/actix_web/struct.Scope.html#avoid-trailing-slashes","messagePattern":"scopes should not have trailing slashes; see https://docs\\.rs/actix-web/4/actix_web/struct\\.Scope\\.html#avoid-trailing-slashes","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"actix-web-codegen/src/scope.rs","lineNumber":38,"sourceCode":"            Span::call_site(),\n            \"missing arguments for scope macro, expected: #[scope(\\\"/prefix\\\")]\",\n        ));\n    }\n\n    let scope_prefix = syn::parse::<syn::LitStr>(args.clone()).map_err(|err| {\n        syn::Error::new(\n            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))","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/actix/actix-web/blob/4d435abc281842f3cbee165b6cde739e001d3a25/actix-web-codegen/src/scope.rs#L20-L56","documentation":"This compile-time error fires when the scope prefix string ends with a trailing slash (e.g., `\"/api/\"`). The check at line 34 detects this and rejects it because trailing slashes in scope prefixes cause non-obvious routing problems — the combined route paths end up with double slashes or unexpected matching behavior.","triggerScenarios":"Writing `#[scope(\"/api/\")]` with a trailing slash. The combined route paths would become `\"/api//users\"` which can lead to incorrect matches or 404s.","commonSituations":"Copy-pasting a URL prefix that includes a trailing slash, or following a convention from another framework where trailing slashes are the norm.","solutions":["Remove the trailing slash from the scope prefix: `#[scope(\"/api\")]`","The individual route paths inside the scope should start with `/`: `#[get(\"/users\")]` produces the combined path `/api/users`","If the root of the scope needs to be handled, use `#[get(\"\")]` inside the scope"],"exampleFix":"// before\n#[scope(\"/api/\")]\nmod api {\n    #[get(\"/users\")]\n    async fn users() -> impl Responder { ... }\n}\n\n// after\n#[scope(\"/api\")]\nmod api {\n    #[get(\"/users\")]\n    async fn users() -> impl Responder { ... }\n}","handlingStrategy":"validation","validationCode":"// Validate the scope prefix does not end with a trailing slash.\n// This is a compile-time check, but you can apply the same rule to runtime paths.\nfn validate_scope_prefix(prefix: &str) -> Result<(), String> {\n    if prefix.ends_with('/') {\n        Err(format!(\"Scope prefix '{}' has a trailing slash\", prefix))\n    } else {\n        Ok(())\n    }\n}","typeGuard":"fn has_no_trailing_slash(prefix: &str) -> bool {\n    !prefix.ends_with('/')\n}","tryCatchPattern":null,"preventionTips":["Never include a trailing slash in scope prefixes: use #[scope(\"/api\")] not #[scope(\"/api/\")]","Individual routes inside the scope should start with '/': #[get(\"/users\")]","For the scope root, use #[get(\"\")] inside the scoped module"],"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"}