FuelLabs/sway · error · anyhow::Error

missing path for new command

Error message

missing path for new command

What it means

forc new falls back to the final path component as the project name when --name is absent; Path::file_name() returns None for paths with no final component — a path ending in '..' or a root like '/' — and this ok_or_else converts that into "missing path for new command" before validate_project_name ever runs.

Source

Thrown at forc/src/cli/commands/new.rs:65

    let Command {
        contract,
        script,
        predicate,
        library,
        workspace,
        name,
        path,
    } = command;

    match &name {
        Some(name) => validate_project_name(name)?,
        None => {
            // If there is no name specified for the project, the last component of the `path` (directory name)
            // will be used by default so we should also check that.
            let project_path = PathBuf::from(&path);
            let directory_name = project_path
                .file_name()
                .ok_or_else(|| anyhow!("missing path for new command"))?
                .to_string_lossy();
            validate_project_name(&directory_name)?;
        }
    }

    let dir_path = Path::new(&path);
    if dir_path.exists() {
        forc_result_bail!(
            "Directory \"{}\" already exists.\nIf you wish to initialise a forc project inside \
            this directory, consider using `forc init --path {}`",
            dir_path.canonicalize()?.display(),
            dir_path.display(),
        );
    } else {
        std::fs::create_dir_all(dir_path)?;
    }

    let init_cmd = InitCommand {

View on GitHub (pinned to 47e5e902fa)

Solutions

  1. Pass an explicit project name: `forc new --name myproj --path <dir>`
  2. Give a path whose last component is a real directory name (no trailing '..' or '/')
  3. Sanitize script variables so empty strings don't turn the path into '..'

Example fix

# before
forc new --path ..

# after
forc new --name my_project --path ../my_project
Defensive patterns

Strategy: validation

Validate before calling

// Mirror forc's own logic: without --name the last path component becomes the project name.
let name = match (&command.name, std::path::Path::new(&command.path).file_name()) {
    (Some(n), _) => n.clone(),
    (None, Some(last)) => last.to_string_lossy().into_owned(),
    (None, None) => anyhow::bail!("--path must end in a directory name, or pass --name"),
};

Type guard

fn path_has_file_name(p: &str) -> bool {
    std::path::Path::new(p).file_name().is_some()
}

Prevention

When it happens

Trigger: `forc new --path ..`, `forc new --path .` is fine ('.' has file_name "."), but `--path ..` or `--path /` yields None. Concretely any path whose last component normalizes to a parent reference or the filesystem root.

Common situations: Shell scripts computing a destination path that collapses to '..' (e.g. joining an empty variable), or invoking forc new at the filesystem root / with a trailing '..' in CI.

Related errors


AI-assisted analysis of FuelLabs/sway@47e5e902fa (2026-08-16). Data as JSON: /api/errors/e8f1198b15916e27. Report an issue: GitHub.