{"id":"80f6bffebab19ace","repo":"rust-lang/cargo","slug":"subcommand-is-required-add-a-subcommand-to-the-co","errorCode":null,"errorMessage":"subcommand is required, add a subcommand to the command alias `alias.{cmd}`","messagePattern":"subcommand is required, add a subcommand to the command alias `alias\\.(.+?)`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/bin/cargo/cli.rs","lineNumber":377,"sourceCode":"                let mut alias = alias\n                    .into_iter()\n                    .map(|s| OsString::from(s))\n                    .collect::<Vec<_>>();\n                alias.extend(\n                    sub_args\n                        .get_many::<OsString>(\"\")\n                        .unwrap_or_default()\n                        .cloned(),\n                );\n                // new_args strips out everything before the subcommand, so\n                // capture those global options now.\n                // Note that an alias to an external command will not receive\n                // these arguments. That may be confusing, but such is life.\n                let global_args = GlobalArgs::new(sub_args);\n                let new_args = cli(gctx).no_binary_name(true).try_get_matches_from(alias)?;\n\n                let Some(new_cmd) = new_args.subcommand_name() else {\n                    return Err(anyhow!(\n                        \"subcommand is required, add a subcommand to the command alias `alias.{cmd}`\"\n                    )\n                        .into());\n                };\n\n                already_expanded.push(cmd.to_string());\n                if already_expanded.contains(&new_cmd.to_string()) {\n                    // Crash if the aliases are corecursive / unresolvable\n                    return Err(anyhow!(\n                        \"alias {} has unresolvable recursive definition: {} -> {}\",\n                        already_expanded[0],\n                        already_expanded.join(\" -> \"),\n                        new_cmd,\n                    )\n                    .into());\n                }\n\n                let (expanded_args, _) = expand_aliases(gctx, new_args, already_expanded)?;","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/rust-lang/cargo/blob/0e07a155371a6ce88ae53a2c00df940280c09a67/src/bin/cargo/cli.rs#L359-L395","documentation":"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}.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Edit .cargo/config.toml so the alias starts with a valid cargo subcommand, e.g. `foo = \"build --release\"`.","If the alias targets an external command, install `cargo-<name>` (it must be on PATH).","Check for typos: the first token must exactly match a known subcommand.","Run `cargo help` to list valid builtins the alias can invoke."],"exampleFix":"# before (.cargo/config.toml)\n[alias]\nfoo = [\"--verbose\"]\n\n# after\n[alias]\nfoo = \"build --verbose\"","handlingStrategy":"validation","validationCode":"// Validate an alias definition starts with a known subcommand token\nfn alias_has_subcommand(def: &[String], known: &std::collections::HashSet<String>) -> bool {\n    def.iter().next()\n        .map(|t| known.contains(t))\n        .unwrap_or(false)\n}","typeGuard":"fn is_well_formed_alias(def: &str) -> bool {\n    let first = def.split_whitespace().next();\n    first.is_some() && !first.unwrap().starts_with('-')\n}","tryCatchPattern":null,"preventionTips":["Always begin an alias definition with a concrete subcommand name.","Lint .cargo/config.toml aliases in CI (parse and check the first token).","Install external cargo-<ext> commands before aliasing to them."],"tags":["cargo","alias","config","cli"],"analyzedSha":"0e07a155371a6ce88ae53a2c00df940280c09a67","analyzedAt":"2026-08-06T01:46:58.334Z","schemaVersion":2}