Hmbown/CodeWhale · error

expected exec command

Error message

expected exec command

What it means

Test-only panic in crates/tui/src/lib.rs:15430. The test `exec_accepts_split_prompt_words_for_windows_cmd_shims` parses ["codewhale","exec","hello","world"] and destructures `Commands::Exec(args)` via let-else; if parsing yields another variant or None, it panics with "expected exec command". The point under test is that unflagged words after `exec` stay in `args.prompt` instead of being absorbed elsewhere.

Solutions

  1. Verify `Commands::Exec(ExecArgs)` is still a declared subcommand in the Commands enum.
  2. Panic with the actual parsed value (`got {:?}`) to identify what clap produced instead.
  3. Ensure top-level multi-value args do not shadow the subcommand; clap only parses subcommands before free-standing positional values.
  4. Run `cargo test -p codewhale-tui --lib exec_accepts_split_prompt_words` after any Cli struct change.
Defensive patterns

Strategy: validation

Validate before calling

match cli.command {
    Some(Commands::Exec(ref args)) => assert_eq!(args.prompt, vec!["hello", "world"]),
    other => panic!("expected exec command, got {other:?}"),
}

Type guard

fn as_exec(cmd: &Option<Commands>) -> Option<&ExecArgs> {
    match cmd { Some(Commands::Exec(a)) => Some(a), _ => None }
}

Prevention

When it happens

Trigger: parse_cli of `exec hello world` does not produce `Commands::Exec` — the `exec` subcommand was renamed/aliased away, or a new top-level argument captured "exec"/the prompt words so `cli.command` is None.

Common situations: Adding a global catch-all `prompt: Vec<String>` (num_args=1..) at the Cli level that eats "exec"; renaming `Commands::Exec`; breaking the subcommand dispatch while refactoring FeatureToggles.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/1c5290161bc7fc99. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/lib.rs:15430

        assert_eq!(execution.default_model(), "routed-legacy-model");
        assert_eq!(execution.deepseek_base_url(), "http://127.0.0.1:18183/v1");
        assert_eq!(execution.deepseek_api_key().unwrap(), "legacy-root-key");
        for _ in 0..2 {
            let identity = execution
                .resolve_provider_identity("custom")
                .expect("legacy identity remains repeatedly resolvable");
            assert_eq!(identity.key, "custom");
        }
        let client =
            crate::client::DeepSeekClient::new(&execution).expect("legacy execution client");
        assert_eq!(client.base_url(), "http://127.0.0.1:18183/v1");
    }

    #[test]
    fn exec_accepts_split_prompt_words_for_windows_cmd_shims() {
        let cli = parse_cli(&["codewhale", "exec", "hello", "world"]);
        let Some(Commands::Exec(args)) = cli.command else {
            panic!("expected exec command");
        };

        assert_eq!(args.prompt, vec!["hello", "world"]);
    }

    #[test]
    fn exec_keeps_model_flag_before_split_prompt_words() {
        let cli = parse_cli(&["codewhale", "exec", "--model", "auto", "hello", "world"]);
        let Some(Commands::Exec(args)) = cli.command else {
            panic!("expected exec command");
        };

        assert_eq!(args.model.as_deref(), Some("auto"));
        assert_eq!(args.prompt, vec!["hello", "world"]);
    }

    #[test]
    fn exec_keeps_flags_before_split_prompt_words() {

View on GitHub (pinned to 433685b202)