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

File path is invalid: {path}

Error message

File path is invalid: {path}

What it means

Returned by proc-macro-srv's Windows-only ensure_file_with_lock_free_access when path.file_stem() returns None - i.e. the supplied library path has no valid file-name stem (empty, ends in '..', or is a root/directory path). std raises ErrorKind::InvalidInput with the offending path interpolated. The function exists to copy the proc-macro dylib to a temp dir so Windows does not lock the original.

Source

Thrown at src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs:112

}

/// Copy the dylib to temp directory to prevent locking in Windows
#[cfg(windows)]
fn ensure_file_with_lock_free_access(
    temp_dir: &TempDir,
    path: &Utf8Path,
) -> io::Result<Utf8PathBuf> {
    use std::collections::hash_map::RandomState;
    use std::hash::{BuildHasher, Hasher};

    if std::env::var("RA_DONT_COPY_PROC_MACRO_DLL").is_ok() {
        return Ok(path.to_path_buf());
    }

    let mut to = Utf8Path::from_path(temp_dir.path()).unwrap().to_owned();

    let file_name = path.file_stem().ok_or_else(|| {
        io::Error::new(io::ErrorKind::InvalidInput, format!("File path is invalid: {path}"))
    })?;

    to.push({
        // Generate a unique number by abusing `HashMap`'s hasher.
        // Maybe this will also "inspire" a libs team member to finally put `rand` in libstd.
        let unique_name = RandomState::new().build_hasher().finish();
        format!("{file_name}-{unique_name}.dll")
    });
    fs::copy(path, &to)?;
    Ok(to)
}

#[cfg(unix)]
fn ensure_file_with_lock_free_access(
    _temp_dir: &TempDir,
    path: &Utf8Path,
) -> io::Result<Utf8PathBuf> {
    Ok(path.to_owned())

View on GitHub (pinned to 7088e4b63a)

Solutions

  1. Inspect the exact path value printed in the error - it has no file stem component.
  2. Clean and rebuild the affected crate (cargo clean -p <crate> && cargo build) so target paths regenerate.
  3. Verify the dylib actually exists at the expected target/<triple>/<profile>/ path before rust-analyzer loads it.
  4. Report/check the cargo metadata if the path originates there; fix the build script producing an empty filename.

Example fix

// Diagnostic: print the path before loading.
println!("dylib path = {:?}", path);
assert!(path.file_stem().is_some(), "path has no file stem");
// Then rebuild: cargo clean -p my-crate && cargo build
Defensive patterns

Strategy: validation

Validate before calling

fn valid_dylib_path(path: &std::path::Path) -> io::Result<()> {
    match path.file_stem() {
        Some(_) => Ok(()),
        None => Err(io::Error::new(io::ErrorKind::InvalidInput,
            format!("path has no file stem: {path:?}"))),
    }
}

Type guard

fn has_file_stem(p: &std::path::Path) -> bool {
    p.file_stem().map(|s| !s.is_empty()).unwrap_or(false)
}

Try / catch

match ensure_file_with_lock_free_access(&tmp, &path) {
    Ok(p) => Ok(p),
    Err(e) if e.kind() == io::ErrorKind::InvalidInput
        && e.to_string().contains("File path is invalid") => {
        // clean & rebuild the crate, then retry load
        Err(e)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Loading a proc-macro dylib on Windows where the path passed to load_dylib has no file_stem: an empty string, a path ending in a separator, '..', or a volume root like "C:\". Rust-analyzer invokes this when expanding macros from a crate whose dylib path is malformed.

Common situations: Corrupted/empty OUT_DIR or target dir producing a bad dylib path; a build script emitting a malformed path; symlinks resolving to a root; cargo metadata returning an anomalous path.

Related errors


AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10). Data as JSON: /api/errors/9b3b49378293c74f. Report an issue: GitHub.