rust-lang/mdBook · error
Shell name missing.
Error message
Shell name missing.
What it means
mdbook's `completions` subcommand reads the shell type from the `shell` argument via `ArgMatches::get_one::<Shell>("shell")`. If the value is absent from the parsed matches, the code raises this anyhow error instead of panicking on an Option unwrap. In practice clap's required-argument definition makes this nearly unreachable; it is a defensive guard.
Source
Thrown at src/main.rs:36
fn main() {
init_logger();
let command = create_clap_command();
// Check which subcommand the user ran...
let res = match command.get_matches().subcommand() {
Some(("init", sub_matches)) => cmd::init::execute(sub_matches),
Some(("build", sub_matches)) => cmd::build::execute(sub_matches),
Some(("clean", sub_matches)) => cmd::clean::execute(sub_matches),
#[cfg(feature = "watch")]
Some(("watch", sub_matches)) => cmd::watch::execute(sub_matches),
#[cfg(feature = "serve")]
Some(("serve", sub_matches)) => cmd::serve::execute(sub_matches),
Some(("test", sub_matches)) => cmd::test::execute(sub_matches),
Some(("completions", sub_matches)) => (|| {
let shell = sub_matches
.get_one::<Shell>("shell")
.ok_or_else(|| anyhow!("Shell name missing."))?;
let mut complete_app = create_clap_command();
clap_complete::generate(
*shell,
&mut complete_app,
"mdbook",
&mut std::io::stdout().lock(),
);
Ok(())
})(),
_ => unreachable!(),
};
if let Err(e) = res {
utils::log_backtrace(&e);
std::process::exit(101);
}View on GitHub (pinned to dc21064fc2)
Solutions
- Pass the shell argument explicitly: `mdbook completions bash` (or zsh/fish/powershell/elvish).
- Check shell completion script installation docs; most shells source `mdbook completions <shell>` output once.
- If invoking internally, build matches through `create_clap_command().get_matches()` rather than hand-crafting ArgMatches.
- Verify no shell alias/wrapper is dropping the argument.
Example fix
// before (hand-built matches, missing arg)
let matches = Command::new("completions").get_matches_from(["mdbook"]);
// after
let matches = Command::new("completions")
.arg(Arg::new("shell").required(true))
.get_matches_from(["mdbook", "completions", "bash"]); Defensive patterns
Strategy: validation
Validate before calling
if sub_matches.get_one::<Shell>("shell").is_none() {
eprintln!("usage: mdbook completions <bash|zsh|fish|powershell|elvish>");
std::process::exit(2);
} Try / catch
let shell = sub_matches
.get_one::<Shell>("shell")
.ok_or_else(|| anyhow!("Shell name missing."))?; // propagate instead of unwrap Prevention
- Always pass the shell argument to `mdbook completions`.
- Keep the `shell` arg defined with `.required(true)` in create_clap_command.
- Build ArgMatches through the real clap Command, not by hand.
- Add a CI test that runs `mdbook completions bash` end-to-end.
When it happens
Trigger: Running `mdbook completions` without providing the required shell argument in a way that bypasses clap's validation — e.g. invoking the closure logic programmatically with hand-built or empty ArgMatches, or a clap definition change removing `.required(true)` / possible values from the `shell` arg.
Common situations: Programmatic re-use of the completions branch with constructed ArgMatches; downgrading or patching mdbook where the `shell` arg constraint changed; scripted invocations that strip arguments.
Related errors
AI-assisted analysis of rust-lang/mdBook@dc21064fc2 (2026-09-01).
Data as JSON: /api/errors/00698e0272c63f2a.
Report an issue: GitHub.