actix/actix-web · warning · io::Error

No such file

Error message

No such file

What it means

An io::Error of kind NotFound with message "No such file" is the fallback used by the Files service (service.rs:290) when directory traversal completes without ever recording a NotFound/NotADirectory miss. It is passed to handle_err, which by default produces a 404 response. In practice most 404s come from the stored last_miss IO error; this string is the edge-case default when no open was even attempted.

Solutions

  1. Verify the directory configured in Files::new(...) exists and is readable by the server process.
  2. Set an index file via .index_file("index.html") and/or enable .show_files(true) for listing.
  3. Register a custom default handler (App::default_service) to render a friendly 404 page.

Example fix

// before
App::new().service(Files::new("/assets", "/nonexistent/dir"))

// after
App::new().service(
    Files::new("/assets", "/srv/site/assets")
        .index_file("index.html")
)
Defensive patterns

Strategy: fallback

Validate before calling

// Confirm the served directory exists at startup
let root = Path::new(SERVE_DIR);
assert!(root.is_dir(), "static dir missing: {SERVE_DIR}");

Try / catch

// Provide a friendly 404 fallback
App::new()
    .service(Files::new("/assets", SERVE_DIR).index_file("index.html"))
    .default_service(web::to(|| HttpResponse::NotFound().body("not found")))

Prevention

When it happens

Trigger: A request maps to a directory that exists but contains no index file, directory listing is disabled, and no candidate file open produced a NotFound error - e.g. an empty resolved path or a config where index/show_index are both off and the target is an unrenderable directory branch.

Common situations: Misconfigured Files::new root pointing at a missing directory; index file not set and listing disabled; deploy where static assets were not copied into the served directory.

Related errors


AI-assisted analysis of actix/actix-web@7ae209e4a4 (2026-08-09). Data as JSON: /api/errors/86bbefaff1a0b57b. Report an issue: GitHub.

Appendix: source

Thrown at actix-files/src/service.rs:290

                        }
                        Err(err) => return this.handle_err(err, req).await,
                    }
                }
            }

            if let Some((base, path)) = first_index_listing {
                return Ok(this.show_index(req, base, path));
            }

            if found_unrenderable_dir {
                return Ok(ServiceResponse::from_err(
                    FilesError::IsDirectory,
                    req.into_parts().0,
                ));
            }

            let err = last_miss
                .unwrap_or_else(|| io::Error::new(io::ErrorKind::NotFound, "No such file"));
            this.handle_err(err, req).await
        })
    }
}

/// Flate doesn't have an accepted file extension, so it is not included here.
const SUPPORTED_PRECOMPRESSION_ENCODINGS: &[header::ContentEncoding] = &[
    header::ContentEncoding::Brotli,
    header::ContentEncoding::Gzip,
    header::ContentEncoding::Zstd,
    header::ContentEncoding::Identity,
];

/// Searches disk for an acceptable alternate encoding of the content at the given path, as
/// preferred by the request's `Accept-Encoding` header. Returns the corresponding `NamedFile` with
/// the most appropriate supported encoding, if any exist.
async fn find_compressed(
    req: &ServiceRequest,

View on GitHub (pinned to 7ae209e4a4)