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

  1. Pass the shell argument explicitly: `mdbook completions bash` (or zsh/fish/powershell/elvish).
  2. Check shell completion script installation docs; most shells source `mdbook completions <shell>` output once.
  3. If invoking internally, build matches through `create_clap_command().get_matches()` rather than hand-crafting ArgMatches.
  4. 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

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.