rust-lang/cargo · error · io::Error

the path was not found

Error message

the path was not found

What it means

`try_canonicalize` is a Windows-only helper (`#[cfg(windows)]`). `std::fs::canonicalize` on Windows can fail for various path forms, so the function falls back: first it re-checks existence with `try_exists()`; if the path does not exist it returns `io::Error::new(ErrorKind::NotFound, "the path was not found")`; otherwise it falls through to `std::path::absolute(&path)`. This preserves `canonicalize`'s behavior of erroring on non-existent paths while still returning an absolute path when canonicalization itself is the problem.

Solutions

  1. Verify the path exists (create the file/directory, or fix the typo) before canonicalizing.
  2. Check the working directory and that build artifacts have been generated prior to this call.
  3. For UNC/network paths, confirm the share is reachable and the path is correct.

Example fix

// before (Windows)
let p = try_canonicalize("C:\\build\\missing.exe")?; // NotFound

// after
std::fs::create_dir_all("C:\\build")?;
// ensure the file exists first, then canonicalize
let p = try_canonicalize("C:\\build\\real.exe")?;
Defensive patterns

Strategy: validation

Validate before calling

use std::path::Path;
fn exists_before_canon(p: &Path) -> std::io::Result<bool> { p.try_exists() }
// on Windows, call this before try_canonicalize to surface a clear NotFound up front

Try / catch

match try_canonicalize(path) {
    Ok(p) => { /* use p */ }
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
        // create the file/dir, or correct the path, then retry
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling `try_canonicalize` on a Windows path where `std::fs::canonicalize` fails AND `path.as_ref().try_exists()?` returns `false` (the file genuinely does not exist). The explicit `NotFound` error is returned.

Common situations: Passing a non-existent path on Windows (typo, deleted file, not-yet-created build artifact, wrong working directory), or a path on a network/UNC location that cannot be resolved and does not exist.

Related errors


AI-assisted analysis of rust-lang/cargo@98a09e7e7d (2026-08-11). Data as JSON: /api/errors/f1413f5886f863c3. Report an issue: GitHub.

Appendix: source

Thrown at src/util/mod.rs:160

}

#[cfg(not(windows))]
#[inline]
pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> {
    std::fs::canonicalize(&path)
}

#[cfg(windows)]
#[inline]
pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> {
    use std::io::Error;
    use std::io::ErrorKind;

    // On Windows `canonicalize` may fail, so we fall back to getting an absolute path.
    std::fs::canonicalize(&path).or_else(|_| {
        // Return an error if a file does not exist for better compatibility with `canonicalize`
        if !path.as_ref().try_exists()? {
            return Err(Error::new(ErrorKind::NotFound, "the path was not found"));
        }
        std::path::absolute(&path)
    })
}

/// Get the current [`umask`] value.
///
/// [`umask`]: https://man7.org/linux/man-pages/man2/umask.2.html
#[cfg(unix)]
pub fn get_umask() -> u32 {
    use std::sync::OnceLock;
    static UMASK: OnceLock<libc::mode_t> = OnceLock::new();
    // SAFETY: Syscalls are unsafe. Calling `umask` twice is even unsafer for
    // multithreading program, since it doesn't provide a way to retrieve the
    // value without modifications. We use a static `OnceLock` here to ensure
    // it only gets call once during the entire program lifetime.
    *UMASK.get_or_init(|| unsafe {
        let umask = libc::umask(0o022);

View on GitHub (pinned to 98a09e7e7d)