Hmbown/CodeWhale · error

Model name cannot be empty

Error message

Model name cannot be empty

What it means

Model subcommand argument validation: a model was explicitly supplied as an empty string. An explicitly requested model must be non-empty because an empty id cannot be resolved against any provider; the guard fires before the command runs.

Solutions

  1. Pass a non-empty model name: `codewhale model set <model>`.
  2. Check the source variable in scripts: `echo "$MODEL"` to confirm it is populated.
  3. Use `codewhale model list` (or providers export) to find valid model names.

Example fix

// before
codewhale model set "$MODEL"   # MODEL empty
// after
: "${MODEL:?MODEL must be set}" && codewhale model set "$MODEL"
Defensive patterns

Strategy: validation

Validate before calling

let trimmed = model.trim();
if trimmed.is_empty() {
    eprintln!("refusing to call 'model set' with an empty name");
    std::process::exit(2);
}

Try / catch

if let Err(e) = run_model_set(model) {
    if e.to_string() == "Model name cannot be empty" {
        eprintln!("$MODEL is unset or blank; export MODEL=<name> first");
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: Running `codewhale model set ""` or `codewhale model set " "` — trimmed.is_empty() — before canonical_model_for_set is applied.

Common situations: Shell variable holding the model name is empty/unset; copy-paste dropped the model id; scripted invocation with a missing positional argument consumed as empty string.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/46d65065f8684ef0. Report an issue: GitHub.

Appendix: source

Thrown at crates/cli/src/lib.rs:4887

            );
            println!(
                "model_source: {}",
                if queried.is_some() {
                    "argument"
                } else {
                    // This branch is reachable only for an explicit
                    // subcommand provider with no requested model. The model
                    // therefore came from that provider's default, not from
                    // the configured runtime route we deliberately overrode.
                    "provider default"
                }
            );
            Ok(())
        }
        ModelCommand::Set { model } => {
            let trimmed = model.trim();
            if trimmed.is_empty() {
                bail!("Model name cannot be empty");
            }
            let canonical = canonical_model_for_set(trimmed);
            codewhale_tui::route_preferences::set(store.path(), "model", canonical)?;
            store.reload()?;
            println!("Default model set to '{canonical}'");
            Ok(())
        }
    }
}

/// The TUI passthrough a thread subcommand delegates as, if it delegates.
///
/// Exhaustive on purpose: a future `ThreadCommand` variant that starts a
/// session has to state its passthrough here, where the caller below routes it
/// through the one command builder that applies the telemetry floor.
fn thread_delegation(command: &ThreadCommand) -> Option<Vec<String>> {
    match command {
        ThreadCommand::Resume { thread_id } => Some(vec!["resume".to_string(), thread_id.clone()]),

View on GitHub (pinned to 73e0f67d83)