rust-lang/cargo · error

subcommand is required, add a subcommand to the command alia

Error message

subcommand is required, add a subcommand to the command alias `alias.{cmd}`

What it means

From expand_aliases (src/bin/cargo/cli.rs:376-381). After resolving a user alias from config, Cargo re-parses the alias's argument list with no_binary_name and reads new_args.subcommand_name(). If there is no subcommand (the alias consists only of flags, is empty, or names something that isn't a builtin/external command), it errors asking you to add a subcommand to alias.{cmd}.

Source

Thrown at src/bin/cargo/cli.rs:377

                let mut alias = alias
                    .into_iter()
                    .map(|s| OsString::from(s))
                    .collect::<Vec<_>>();
                alias.extend(
                    sub_args
                        .get_many::<OsString>("")
                        .unwrap_or_default()
                        .cloned(),
                );
                // new_args strips out everything before the subcommand, so
                // capture those global options now.
                // Note that an alias to an external command will not receive
                // these arguments. That may be confusing, but such is life.
                let global_args = GlobalArgs::new(sub_args);
                let new_args = cli(gctx).no_binary_name(true).try_get_matches_from(alias)?;

                let Some(new_cmd) = new_args.subcommand_name() else {
                    return Err(anyhow!(
                        "subcommand is required, add a subcommand to the command alias `alias.{cmd}`"
                    )
                        .into());
                };

                already_expanded.push(cmd.to_string());
                if already_expanded.contains(&new_cmd.to_string()) {
                    // Crash if the aliases are corecursive / unresolvable
                    return Err(anyhow!(
                        "alias {} has unresolvable recursive definition: {} -> {}",
                        already_expanded[0],
                        already_expanded.join(" -> "),
                        new_cmd,
                    )
                    .into());
                }

                let (expanded_args, _) = expand_aliases(gctx, new_args, already_expanded)?;

View on GitHub (pinned to 0e07a15537)

Solutions

  1. Edit .cargo/config.toml so the alias starts with a valid cargo subcommand, e.g. `foo = "build --release"`.
  2. If the alias targets an external command, install `cargo-<name>` (it must be on PATH).
  3. Check for typos: the first token must exactly match a known subcommand.
  4. Run `cargo help` to list valid builtins the alias can invoke.

Example fix

# before (.cargo/config.toml)
[alias]
foo = ["--verbose"]

# after
[alias]
foo = "build --verbose"
Defensive patterns

Strategy: validation

Validate before calling

// Validate an alias definition starts with a known subcommand token
fn alias_has_subcommand(def: &[String], known: &std::collections::HashSet<String>) -> bool {
    def.iter().next()
        .map(|t| known.contains(t))
        .unwrap_or(false)
}

Type guard

fn is_well_formed_alias(def: &str) -> bool {
    let first = def.split_whitespace().next();
    first.is_some() && !first.unwrap().starts_with('-')
}

Prevention

When it happens

Trigger: A .cargo/config.toml entry like [alias] foo = "" or alias.foo = ["--verbose"]. An alias whose first token is neither a builtin subcommand, a builtin alias, nor an installed cargo-<ext> external. Programmatically building an alias config without a leading command token.

Common situations: Typo in the alias definition; alias referencing a command that isn't installed yet; refactoring config and leaving a dangling alias; an alias meant to forward args but missing the target command.

Related errors


AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06). Data as JSON: /data/errors/80f6bffebab19ace.json. Report an issue: GitHub.