{"record":{"id":"46d65065f8684ef0","repo":"Hmbown/CodeWhale","slug":"model-name-cannot-be-empty","errorCode":null,"errorMessage":"Model name cannot be empty","messagePattern":"Model name cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/lib.rs","lineNumber":4887,"sourceCode":"            );\n            println!(\n                \"model_source: {}\",\n                if queried.is_some() {\n                    \"argument\"\n                } else {\n                    // This branch is reachable only for an explicit\n                    // subcommand provider with no requested model. The model\n                    // therefore came from that provider's default, not from\n                    // the configured runtime route we deliberately overrode.\n                    \"provider default\"\n                }\n            );\n            Ok(())\n        }\n        ModelCommand::Set { model } => {\n            let trimmed = model.trim();\n            if trimmed.is_empty() {\n                bail!(\"Model name cannot be empty\");\n            }\n            let canonical = canonical_model_for_set(trimmed);\n            codewhale_tui::route_preferences::set(store.path(), \"model\", canonical)?;\n            store.reload()?;\n            println!(\"Default model set to '{canonical}'\");\n            Ok(())\n        }\n    }\n}\n\n/// The TUI passthrough a thread subcommand delegates as, if it delegates.\n///\n/// Exhaustive on purpose: a future `ThreadCommand` variant that starts a\n/// session has to state its passthrough here, where the caller below routes it\n/// through the one command builder that applies the telemetry floor.\nfn thread_delegation(command: &ThreadCommand) -> Option<Vec<String>> {\n    match command {\n        ThreadCommand::Resume { thread_id } => Some(vec![\"resume\".to_string(), thread_id.clone()]),","sourceCodeStart":4869,"sourceCodeEnd":4905,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/cli/src/lib.rs#L4869-L4905","documentation":"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.","triggerScenarios":"Running `codewhale model set \"\"` or `codewhale model set \"   \"` — trimmed.is_empty() — before canonical_model_for_set is applied.","commonSituations":"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.","solutions":["Pass a non-empty model name: `codewhale model set <model>`.","Check the source variable in scripts: `echo \"$MODEL\"` to confirm it is populated.","Use `codewhale model list` (or providers export) to find valid model names."],"exampleFix":"// before\ncodewhale model set \"$MODEL\"   # MODEL empty\n// after\n: \"${MODEL:?MODEL must be set}\" && codewhale model set \"$MODEL\"","handlingStrategy":"validation","validationCode":"let trimmed = model.trim();\nif trimmed.is_empty() {\n    eprintln!(\"refusing to call 'model set' with an empty name\");\n    std::process::exit(2);\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = run_model_set(model) {\n    if e.to_string() == \"Model name cannot be empty\" {\n        eprintln!(\"$MODEL is unset or blank; export MODEL=<name> first\");\n    } else { return Err(e); }\n}","preventionTips":["Guard shell variables with :? before interpolating into CLI args.","Use `codewhale model list` to pick a concrete model id instead of typing from memory.","In scripts, assert the model argument is non-empty before dispatching."],"tags":["cli","model","validation"],"backgroundTag":"empty-required-field","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}