seanmonstar/warp · error · FileOpenError

file_open_error

Error message

file_open_error

What it means

FileOpenError is the rejection returned by warp::fs::file / file_reply (src/filters/fs.rs) when std::fs::File::open on the requested path fails. The path was resolved but could not be opened, most commonly because it does not exist or the process lacks read permission. The error is logged (the underlying io::Error is printed) and a generic file_open_error rejection is returned so internals are not leaked.

Solutions

  1. Verify the file exists at the exact path (use an absolute path in warp::fs::file)
  2. Check the file's permissions and the user the server process runs as
  3. Confirm relative paths resolve from the process working directory, not the crate root
  4. If serving a directory, use warp::fs::dir instead of fs::file
  5. Check the server log next to this rejection: the real io::Error is printed there

Example fix

// before
let route = warp::path("report").and(warp::fs::file("out/report.pdf"));
// after
let route = warp::path("report")
    .and(warp::fs::file("/var/www/assets/report.pdf"));
Defensive patterns

Strategy: validation

Validate before calling

// check before serving
let path = std::path::Path::new("/var/www/assets/report.pdf");
if !path.is_file() {
    eprintln!("missing or not a file: {}", path.display());
}
match std::fs::File::open(path) {
    Ok(_) => (),
    Err(e) => eprintln!("cannot open {}: {}", path.display(), e),
}

Type guard

fn is_readable_file(p: &str) -> bool {
    std::fs::File::open(p).is_ok()
}

Try / catch

let route = warp::path("report")
    .and(warp::fs::file("/var/www/assets/report.pdf"))
    .recover(|rej: warp::Rejection| async move {
        if rej.find::<warp::reject::FileOpenError>().is_some() {
            Ok(warp::reply::with_status("file unavailable", warp::http::StatusCode::NOT_FOUND))
        } else {
            Err(rej)
        }
    });

Prevention

When it happens

Trigger: warp::fs::file("path") or fs::file_reply used with a path that does not exist, is a directory opened as a file, has a broken symlink, or is unreadable by the server process (permission denied).

Common situations: Relative path resolved against an unexpected working directory; serving static assets where the build output folder wasn't deployed; file deleted between route match and open; Docker container missing the mounted file; running the server as a user without read access to the asset directory.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


AI-assisted analysis of seanmonstar/warp@ff34d7213e (2026-09-09). Data as JSON: /api/errors/6fe4e3202b613176. Report an issue: GitHub.

Appendix: source

Thrown at src/filters/fs.rs:289

            let rej = match err.kind() {
                io::ErrorKind::NotFound => {
                    tracing::debug!("file not found: {:?}", path.as_ref().display());
                    reject::not_found()
                }
                io::ErrorKind::PermissionDenied => {
                    tracing::warn!("file permission denied: {:?}", path.as_ref().display());
                    reject::known(FilePermissionError { _p: () })
                }
                _ => {
                    tracing::error!(
                        "file open error (path={:?}): {} ",
                        path.as_ref().display(),
                        err
                    );
                    reject::known(FileOpenError { _p: () })
                }
            };
            Either::Right(future::err(rej))
        }
    })
}

async fn file_metadata(f: TkFile) -> Result<(TkFile, Metadata), Rejection> {
    match f.metadata().await {
        Ok(meta) => Ok((f, meta)),
        Err(err) => {
            tracing::debug!("file metadata error: {}", err);
            Err(reject::not_found())
        }
    }
}

fn file_conditional(
    f: TkFile,
    path: ArcPath,
    conditionals: Conditionals,

View on GitHub (pinned to ff34d7213e)