{"record":{"id":"6d52d23f50170d9b","repo":"gitbutlerapp/gitbutler","slug":"all-help-topics-have-clap-command-metadata","errorCode":null,"errorMessage":"all help topics have clap command metadata","messagePattern":"all help topics have clap command metadata","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but/src/command/help.rs","lineNumber":52,"sourceCode":"        Some(topic) => print_topic(out, topic),\n        None => print_grouped(out),\n    }\n}\n\npub fn print_grouped(out: &mut OutputChannel) -> std::fmt::Result {\n    let allow_truncation = out.format().allows_truncation();\n    print_grouped_with_truncation(out, allow_truncation)\n}\n\nfn print_topic(out: &mut OutputChannel, topic: HelpTopic) -> std::fmt::Result {\n    use clap::CommandFactory;\n    use std::fmt::Write;\n\n    let mut cmd = Args::command();\n    let topic_command = cmd\n        .find_subcommand_mut(\"help\")\n        .and_then(|help| help.find_subcommand_mut(topic.name()))\n        .expect(\"all help topics have clap command metadata\");\n\n    let t = theme::get();\n    writeln!(out, \"{}\", t.important.paint(topic.title()))?;\n    writeln!(out)?;\n\n    // We can't easily hook into Clap's colorize choice. It's only implemented in\n    // `Command::print_long_help()` and that forces use of `std::io::Stdout`, side-stepping our\n    // OutputChannel implementation.\n    //\n    // A full implementation here would entail using `anstream::AutoStream` along with\n    // `Command::get_color()` and map that to `anstream::ColorChoice`. But just checking if the\n    // output is a terminal is generally sufficient as all modern terminals support ANSI escape\n    // codes, so we'll stay with this simple solution for now.\n    let long_help = topic_command.render_long_help();\n    if out.is_terminal() {\n        writeln!(out, \"{}\", long_help.ansi())\n    } else {\n        writeln!(out, \"{long_help}\")","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/2497b8007aa4a1922dae9a805b32ffe5b5037785/crates/but/src/command/help.rs#L34-L70","documentation":"Invariant panic while printing 'but help <topic>': the code walks the clap command tree (Args::command() -> 'help' -> subcommand named after the topic) and find_subcommand_mut returned None. Every HelpTopic variant must have a same-named clap subcommand registered under 'help'; the panic means the enum and the clap definition drifted apart - a topic added or renamed on one side only.","triggerScenarios":"A maintainer adds a HelpTopic variant without declaring the matching 'help <name>' subcommand; a topic is renamed in the enum but not in the clap definition (or vice versa); conditional compilation drops the subcommand while the enum variant remains.","commonSituations":"Refactors touching help topics; running a locally built binary mid-refactor; generated topic lists drifting from hand-maintained clap registrations.","solutions":["Locate the HelpTopic enum and the clap Args definition; add the missing subcommand with a name equal to topic.name()","If the topic was renamed, align both sides to the same name","Add a test that enumerates every HelpTopic and asserts find_subcommand_mut succeeds for each"],"exampleFix":"// before: HelpTopic::Onboarding exists in the enum, but no matching subcommand is declared\n\n// after: declare the subcommand so names line up with topic.name()\n#[derive(clap::Subcommand)]\nenum HelpSubcommands {\n    Stacks,\n    Onboarding, // must match HelpTopic::Onboarding.name() == \"onboarding\"\n}","handlingStrategy":"validation","validationCode":"// CI test: every help topic must resolve to a clap subcommand\n#[test]\nfn all_help_topics_have_clap_metadata() {\n    use clap::CommandFactory;\n    let mut cmd = Args::command();\n    let help = cmd.find_subcommand_mut(\"help\").expect(\"help subcommand\");\n    for topic in HelpTopic::all() { // adjust to the actual enumeration\n        assert!(help.find_subcommand_mut(topic.name()).is_some(), \"missing: {}\", topic.name());\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the HelpTopic enum and the clap subcommand list in the same file or an adjacent module","Make the topic-to-subcommand name derived (single source of truth) instead of duplicated strings","Run the enumeration test in CI so desync fails the build, not users"],"tags":["rust","panic","clap","help","developer-invariant"],"backgroundTag":"missing-clap-subcommand","analyzedSha":"2497b8007aa4a1922dae9a805b32ffe5b5037785","analyzedAt":"2026-08-17T00:30:25.648Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}