Hmbown/CodeWhale · error · anyhow::Error

Invalid default_text_model

Error message

Invalid default_text_model '{model}' for provider '{}': expected auto or a model ID this provider serves{hint}.

What it means

`default_text_model` must be `auto` or a model ID the active provider actually serves, resolved by `canonical_model_id_for_provider` (each family's own canonical map; unknown IDs pass through only for pass-through providers or custom base URLs). Since #4829 validation uses the active provider's namespace, not DeepSeek's — and the error lists that provider's known model names as examples.

Solutions

  1. Set `default_text_model = "auto"` and let the provider choose.
  2. Use one of the example IDs listed in the error's `(for example: ...)` hint.
  3. If the ID is correct for your own endpoint, route it through that custom provider/base URL so it passes through unvalidated.
  4. Check casing and version suffixes of the model ID.

Example fix

# before
provider = "deepseek"
default_text_model = "gpt-4o"

# after
provider = "deepseek"
default_text_model = "deepseek-chat"
Defensive patterns

Strategy: validation

Validate before calling

fn model_is_acceptable(provider: ApiProvider, model: &str) -> bool {
    model.trim().eq_ignore_ascii_case("auto")
        || provider_passes_model_through(provider)
        || canonical_model_id_for_provider(provider, model).is_some()
}

assert!(model_is_acceptable(active_provider, &config.default_text_model));

Type guard

fn is_valid_model_for_provider(provider: ApiProvider, model: &str) -> bool {
    model.trim().eq_ignore_ascii_case("auto")
        || canonical_model_id_for_provider(provider, model).is_some()
}

Prevention

When it happens

Trigger: `provider = "deepseek"` with `default_text_model = "gpt-4o"`; a typo'd GLM/Kimi/MiniMax model id; mixing a model ID from one family with a different provider.

Common situations: Switching providers without updating the model line; stale IDs after a provider renamed its models; copy-pasting model lists from another provider's docs.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/80f77d1bd8947b0c. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/config.rs:4698

        // (GLM via Z.ai, Kimi, MiniMax, …) and passes unknown ids through, so
        // it rejects only what the provider genuinely cannot serve. Validating
        // with the DeepSeek-only `normalize_model_name` bricked every config
        // whose provider owns a non-DeepSeek family — including ones our own
        // setup wizard writes (`provider = "zai"`, `GLM-5.2`). (#4829)
        if let Some(model) = self.default_text_model.as_deref()
            && !model.trim().eq_ignore_ascii_case("auto")
            && !provider_passes_model_through(self.api_provider())
            && !self.active_provider_preserves_custom_base_url_model()
            && canonical_model_id_for_provider(self.api_provider(), model).is_none()
        {
            let provider = self.api_provider();
            let known = model_completion_names_for_provider(provider);
            let hint = if known.is_empty() {
                String::new()
            } else {
                format!(" (for example: {})", known.join(", "))
            };
            anyhow::bail!(
                "Invalid default_text_model '{model}' for provider '{}': expected auto or a model ID this provider serves{hint}.",
                provider.as_str()
            );
        }
        if let Some(policy) = self.approval_policy.as_deref() {
            let normalized = policy.trim().to_ascii_lowercase();
            if !matches!(
                normalized.as_str(),
                "on-request" | "untrusted" | "never" | "auto" | "suggest"
            ) {
                anyhow::bail!(
                    "Invalid approval_policy '{policy}': expected on-request, untrusted, never, auto, or suggest."
                );
            }
        }
        if let Some(v) = self.verbosity.as_deref() {
            let normalized = v.trim().to_ascii_lowercase();
            if !matches!(normalized.as_str(), "normal" | "concise") {

View on GitHub (pinned to 0c42157ee5)