Hmbown/CodeWhale · error
Model defaults belong to config.toml. Use /model and choose…
Error message
Model defaults belong to config.toml. Use /model and choose Remember as my default, or /config model <id> --save.
What it means
Settings::set deliberately refuses the `default_model`/`model` key: model defaults are owned by config.toml, not session settings. The bail message redirects the user to the /model picker ('Remember as my default') or `/config model <id> --save`. This is an unsupported-operation guard, not a value-format error.
Solutions
- Use the /model command in the TUI and pick 'Remember as my default'.
- Write the model id into config.toml via `/config model <id> --save`.
- Remove default_model from any settings write path; it is not a settable session setting.
Example fix
// before
settings.set("default_model", "glm-5.3-flash")?;
// after
// in the TUI:
// /config model glm-5.3-flash --save
// or edit ~/.config/codewhale/config.toml: model = "glm-5.3-flash" Defensive patterns
Strategy: fallback
Validate before calling
fn is_model_setting_key(key: &str) -> bool {
matches!(key, "default_model" | "model") // always rejected by Settings::set
} Try / catch
match settings.set(key, value) {
Err(e) if e.to_string().contains("Model defaults belong to config.toml") => {
// route to the model config path instead of settings
write_model_to_config_toml(value)?;
}
r => r?,
} Prevention
- Never route model defaults through Settings::set; use /config model <id> --save or config.toml.
- Filter model-related keys out of generic settings-write helpers.
- Update migration scripts that predate this separation.
When it happens
Trigger: Any call to Settings::set("default_model", ...) or Settings::set("model", ...) with any value — the key itself is rejected unconditionally.
Common situations: Users attempting `/config model <id>` without --save, scripts migrating settings files that used to carry default_model, or confusing the settings layer with the config layer.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- A pinned task provider requires an explicit model
- approval log has no parent
- Browser login is only enabled for the canonical Codewhale…
- Failed to update setting: invalid cost currency
- Failed to update setting: invalid max history
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/849f944a04d5580e.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/settings.rs:1748
let max: usize = value.parse().map_err(|_| {
anyhow::anyhow!(
"Failed to update setting: invalid max history '{value}'. Expected a positive number."
)
})?;
self.max_input_history = max;
}
"default_model" | "model" => {
anyhow::bail!(
"Model defaults belong to config.toml. Use /model and choose Remember as my default, or /config model <id> --save."
);
}
"reasoning_effort" | "effort" => {
self.reasoning_effort = normalize_reasoning_effort_setting(value)?;
}
"permission_posture" | "permissions" => {
self.permission_posture = normalize_permission_posture(value);
if self.permission_posture.is_none() {
anyhow::bail!(
"Failed to update setting: invalid permission posture '{value}'. Expected: ask, auto-review, or full-access."
);
}
}
"sandbox_mode" | "sandbox" | "filesystem_sandbox" => {
self.sandbox_mode = normalize_sandbox_mode(value);
if self.sandbox_mode.is_none() {
anyhow::bail!(
"Failed to update setting: invalid sandbox_mode '{value}'. Expected: read-only, workspace-write, danger-full-access, or external-sandbox."
);
}
}
_ => {
anyhow::bail!("Failed to update setting: unknown setting '{key}'.");
}
}
if let Some(canonical) = canonical {
self.provenanceView on GitHub (pinned to 73e0f67d83)