rust-lang/cargo · error

manifest path ` ` is a directory but expected a file

Error message

manifest path `{}` is a directory but expected a file{suggested_path}

What it means

root_manifest() detects that --manifest-path resolves to a directory rather than a file. If that directory contains Cargo.toml, the error appends a help line suggesting the concrete file.

Solutions

  1. Point --manifest-path at the Cargo.toml file inside the directory: `--manifest-path ./mycrate/Cargo.toml`.
  2. Drop --manifest-path and cd into the project; Cargo finds Cargo.toml automatically.

Example fix

# before
# cargo build --manifest-path ./mycrate

# after
# cargo build --manifest-path ./mycrate/Cargo.toml
Defensive patterns

Strategy: validation

Validate before calling

use std::path::Path;

fn resolve_manifest_arg(p: &Path) -> Result<PathBuf, String> {
    let p = paths::normalize_path(p);
    if p.is_dir() {
        let inner = p.join("Cargo.toml");
        if inner.is_file() { return Ok(inner); }
        return Err(format!("{p:?} is a directory; expected a Cargo.toml file"));
    }
    Ok(p)
}

Type guard

fn looks_like_manifest_file(p: &std::path::Path) -> bool {
    p.is_file()
}

Prevention

When it happens

Trigger: Passing a project directory to --manifest-path, e.g. `cargo build --manifest-path ./mycrate` where mycrate is a folder.

Common situations: Confusing the project root directory with the manifest file; copy-pasting a directory from a docs example.

Related errors


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

Appendix: source

Thrown at src/util/command_prelude.rs:1064

    args._values_of_os(name)
}

pub fn root_manifest(manifest_path: Option<&Path>, gctx: &GlobalContext) -> CargoResult<PathBuf> {
    if let Some(manifest_path) = manifest_path {
        let path = gctx.cwd().join(manifest_path);
        // In general, we try to avoid normalizing paths in Cargo,
        // but in this particular case we need it to fix #3586.
        let path = paths::normalize_path(&path);
        if !path.exists() {
            anyhow::bail!("manifest path `{}` does not exist", manifest_path.display())
        } else if path.is_dir() {
            let child_path = path.join("Cargo.toml");
            let suggested_path = if child_path.exists() {
                format!("\nhelp: {} exists", child_path.display())
            } else {
                "".to_string()
            };
            anyhow::bail!(
                "manifest path `{}` is a directory but expected a file{suggested_path}",
                manifest_path.display()
            )
        } else if !path.ends_with("Cargo.toml") && !crate::workspace::parser::is_embedded(&path) {
            if gctx.cli_unstable().script {
                anyhow::bail!(
                    "the manifest-path must be a path to a Cargo.toml or script file: `{}`",
                    path.display()
                )
            } else {
                anyhow::bail!(
                    "the manifest-path must be a path to a Cargo.toml file: `{}`",
                    path.display()
                )
            }
        }
        if crate::workspace::parser::is_embedded(&path) && !gctx.cli_unstable().script {
            anyhow::bail!("embedded manifest `{}` requires `-Zscript`", path.display())

View on GitHub (pinned to 98a09e7e7d)