actix/actix-web · error · io::Error
Provided path has no filename
Error message
Provided path has no filename
What it means
io::Error with kind InvalidInput and message 'Provided path has no filename' (named.rs:99-104) is returned by get_content_type_and_disposition when Path::file_name() returns None — the path's final component is a root or '..'. It propagates out of NamedFile::from_file / open / open_async, which call this helper to derive Content-Type and Content-Disposition. This is a programmer error in the path argument, not a runtime/network condition.
Source
Thrown at actix-files/src/named.rs:100
pub(crate) encoding: Option<ContentEncoding>,
pub(crate) read_mode_threshold: u64,
}
#[cfg(not(feature = "experimental-io-uring"))]
pub(crate) use std::fs::File;
#[cfg(feature = "experimental-io-uring")]
pub(crate) use tokio_uring::fs::File;
use super::chunked;
pub(crate) fn get_content_type_and_disposition(
path: &Path,
) -> Result<(mime::Mime, ContentDisposition), io::Error> {
let filename = match path.file_name() {
Some(name) => name.to_string_lossy(),
None => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Provided path has no filename",
));
}
};
let ct = mime_guess::from_path(path).first_or_octet_stream();
let disposition = match ct.type_() {
mime::IMAGE | mime::TEXT | mime::AUDIO | mime::VIDEO => DispositionType::Inline,
mime::APPLICATION => match ct.subtype() {
mime::JAVASCRIPT | mime::JSON => DispositionType::Inline,
name if name == "wasm" || name == "xhtml" => DispositionType::Inline,
_ => DispositionType::Attachment,
},
_ => DispositionType::Attachment,
};
View on GitHub (pinned to 937960ca67)
Solutions
- Ensure the path passed to NamedFile::open/open_async/from_file has a real filename as its final component.
- Validate user-derived paths with Path::file_name() before constructing a NamedFile.
- Use Files (directory serving) for directory paths instead of NamedFile.
Example fix
// before: path normalises to no filename
NamedFile::open_async(base_dir.join(user_input)).await // user_input could be ".."
// after: require a concrete filename
let name = path.file_name().ok_or_else(||
io::Error::new(io::ErrorKind::InvalidInput, "path must name a file"))?
NamedFile::open_async(base_dir.join(name)).await Defensive patterns
Strategy: validation
Validate before calling
// Validate that the path ends in a real filename before opening.
use std::path::Path;
fn ensure_has_filename(p: &Path) -> io::Result<()> {
if p.file_name().is_none() {
Err(io::Error::new(io::ErrorKind::InvalidInput, "path has no filename"))
} else { Ok(()) }
} Try / catch
// Handle the io::Result from open_async.
match NamedFile::open_async(path).await {
Ok(f) => Ok(f),
Err(e) if e.kind() == io::ErrorKind::InvalidInput => {
// path had no filename; reject the request as 400
Err(actix_web::error::ErrorBadRequest("invalid file path"))
}
Err(e) => Err(e.into()),
} Prevention
- Never derive a NamedFile path directly from raw user input without validation.
- Prefer Path::file_name() to extract just the final component when serving user-named files.
- Use the Files service for directory serving rather than NamedFile on directory-like paths.
When it happens
Trigger: Calling NamedFile::open("/"), NamedFile::open("."), NamedFile::from_file(file, "foo/.."), or any path whose last segment normalises away. file_name() returns None for such paths, hitting the error arm.
Common situations: Building a NamedFile path dynamically from user input or joining that yields a trailing separator, or passing a directory path where a file path was expected.
Related errors
- invalid Range header: invalid syntax
- invalid Range header: range starts after end of content
- No such file
AI-assisted analysis of actix/actix-web@937960ca67 (2026-08-06).
Data as JSON: /data/errors/92c1e49fb15e09db.json.
Report an issue: GitHub.