{"record":{"id":"92c1e49fb15e09db","repo":"actix/actix-web","slug":"provided-path-has-no-filename","errorCode":null,"errorMessage":"Provided path has no filename","messagePattern":"Provided path has no filename","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"actix-files/src/named.rs","lineNumber":96,"sourceCode":"    pub(crate) flags: Flags,\n    pub(crate) status_code: StatusCode,\n    pub(crate) content_type: Mime,\n    pub(crate) content_disposition: ContentDisposition,\n    pub(crate) encoding: Option<ContentEncoding>,\n    pub(crate) read_mode_threshold: u64,\n}\n\npub(crate) use std::fs::File;\n\nuse super::chunked;\n\npub(crate) fn get_content_type_and_disposition(\n    path: &Path,\n) -> Result<(mime::Mime, ContentDisposition), io::Error> {\n    let filename = match path.file_name() {\n        Some(name) => name.to_string_lossy(),\n        None => {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"Provided path has no filename\",\n            ));\n        }\n    };\n\n    let ct = mime_guess::from_path(path).first_or_octet_stream();\n\n    let disposition = match ct.type_() {\n        mime::IMAGE | mime::TEXT | mime::AUDIO | mime::VIDEO => DispositionType::Inline,\n        mime::APPLICATION => match ct.subtype() {\n            mime::JAVASCRIPT | mime::JSON => DispositionType::Inline,\n            name if name == \"wasm\" || name == \"xhtml\" => DispositionType::Inline,\n            _ => DispositionType::Attachment,\n        },\n        _ => DispositionType::Attachment,\n    };\n","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/actix/actix-web/blob/7ae209e4a4f3c8df61cacb9c2d3b8ef28ebda0d6/actix-files/src/named.rs#L78-L114","documentation":"An io::Error of kind InvalidInput with message \"Provided path has no filename\" is returned by get_content_type_and_disposition (named.rs:100) when Path::file_name() returns None. This happens for paths that conceptually have no final component - a trailing \"..\", the root \"/\" (or \"/\"), or an empty path. NamedFile::from_file (named.rs:190) propagates it because it cannot derive a Content-Type or Content-Disposition filename.","triggerScenarios":"Calling NamedFile::open/open_async or from_file with a path like \"/\", \"\", \"..\", or \"/dir/..\" - anything where path.file_name() is None. Also hit indirectly via Files directory service if a computed path resolves to such a form.","commonSituations":"Dynamic path construction joining user input that collapses to root; serving a path that is itself a directory specifier; misconfigured static-file root; symbolic-link resolution landing on \"/\".","solutions":["Validate that the path has a file name before opening: ensure path.file_name().is_some().","Reject or normalize paths containing trailing \"..\" or that equal the root.","Sanitize user-supplied path segments and never let them reach the filesystem unsanitized."],"exampleFix":"// before\nNamedFile::open_async(\"/\").await // Err: no filename\n\n// after\nlet p = std::path::Path::new(\"/srv/site/index.html\");\nassert!(p.file_name().is_some());\nNamedFile::open_async(p).await","handlingStrategy":"validation","validationCode":"// Reject paths without a filename before opening\nfn open_named(p: impl AsRef<Path>) -> Result<NamedFile, io::Error> {\n    let p = p.as_ref();\n    if p.file_name().is_none() {\n        return Err(io::Error::new(io::ErrorKind::InvalidInput, \"no filename\"));\n    }\n    NamedFile::open(p)\n}","typeGuard":"fn has_filename(p: &Path) -> bool {\n    p.file_name().map(|n| !n.is_empty()).unwrap_or(false)\n}","tryCatchPattern":"match NamedFile::open_async(&path).await {\n    Ok(f) => Ok(f.into_response(&req)),\n    Err(e) if e.kind() == io::ErrorKind::InvalidInput =>\n        HttpResponse::BadRequest().finish(),\n    Err(_) => HttpResponse::InternalServerError().finish(),\n}","preventionTips":["Sanitize and normalize user-supplied path segments.","Reject paths equal to root or ending in '..'.","Use actix-files Files service which sanitizes routing internally."],"tags":["filesystem","actix-files","named-file","validation"],"backgroundTag":null,"analyzedSha":"7ae209e4a4f3c8df61cacb9c2d3b8ef28ebda0d6","analyzedAt":"2026-08-09T01:01:40.926Z","contentChangedAt":"2026-08-09T01:01:40.926Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}