{"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":"exception","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/937960ca67f20e14ffe2a075bf6d4593502be12c/actix-web-codegen/src/scope.rs#L20-L56","documentation":"Scope prefixes must not end with a `/`. At actix-web-codegen/src/scope.rs:34-42 the macro rejects a trailing slash because it produces non-obvious routing bugs (double slashes when concatenated with route paths). The message links to the official guidance on avoiding trailing slashes.","triggerScenarios":"`#[scope(\"/api/\")]` — prefix ending in `/`. The macro then concatenates this with inner route paths like `\"/users\"`, yielding `\"/api//users\"`.","commonSituations":"Copying a base URL with a trailing slash from a config/browser, or assuming the framework normalizes slashes.","solutions":["Remove the trailing slash from the scope prefix: `#[scope(\"/api\")]`.","Leave trailing slashes off inner route paths too; rely on the scope prefix + route path joining."],"exampleFix":"// before\n#[scope(\"/api/\")]\nmod api {\n    #[get(\"/users\")]\n    async fn users() -> HttpResponse { ... }\n}\n\n// after\n#[scope(\"/api\")]\nmod api {\n    #[get(\"/users\")]\n    async fn users() -> HttpResponse { ... }\n}","handlingStrategy":"validation","validationCode":"// Compile-time only. Reject trailing slashes in scope prefixes.\n// Quick check: ensure the prefix does not end with '/'.\nfn no_trailing_slash(p: &str) -> bool { !p.ends_with('/') }\n// assert!(no_trailing_slash(\"/api\"));\n// assert!(!no_trailing_slash(\"/api/\"));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Adopt a convention of no trailing slashes anywhere in route/scope paths.","When copying URLs from browsers/config, strip the trailing slash first."],"tags":["rust","actix","actix-web","macro","compile-time","routing"],"analyzedSha":"937960ca67f20e14ffe2a075bf6d4593502be12c","analyzedAt":"2026-08-06T01:15:46.978Z","schemaVersion":2}