Hmbown/CodeWhale · error

custom providers store base_url in their named

Error message

custom providers store base_url in their named [providers.<name>] table

What it means

Custom providers live in a user-chosen [providers.<name>] table, so there is no fixed key for ApiProvider::Custom in provider_base_url_table_key. Persisting a base_url for a custom provider through this static-key path is out of scope (the #1519 constrained slice); the function bails to prevent writing to a wrong/generic key.

Solutions

  1. Use persist_custom_provider instead, which writes the named [providers.<name>] table.
  2. Edit the [providers.<name>] table in the config file directly.

Example fix

// before
persist_provider_base_url_key(config_path, ApiProvider::Custom, &url)?;
// after
persist_custom_provider(config_path, name, &url, None, None, None)?;
Defensive patterns

Strategy: validation

Validate before calling

if matches!(provider, ApiProvider::Custom) { persist_custom_provider(path, name, &url, None, None, None)?; } else { persist_provider_base_url_key(path, provider, &url)?; }

Type guard

fn is_custom(p: ApiProvider) -> bool { matches!(p, ApiProvider::Custom) }

Try / catch

if let Err(e) = persist_provider_base_url_key(path, provider, &url) {
    if e.to_string().contains("custom providers") {
        persist_custom_provider(path, &name, &url, None, None, None)?;
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: Calling persist_provider_base_url_key with ApiProvider::Custom to save a base_url for a custom provider.

Common situations: A script or UI tries to save a custom provider's base_url via the same helper used for built-in providers.

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


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

Appendix: source

Thrown at crates/tui/src/config_persistence.rs:632

        ApiProvider::Mistral => Ok("mistral"),
        ApiProvider::Google => Ok("google"),
        ApiProvider::Antigravity => Ok("antigravity"),
        ApiProvider::Telecomjs => Ok("telecomjs"),
        ApiProvider::Edenai => Ok("edenai"),
        ApiProvider::Zenmux => Ok("zenmux"),
        ApiProvider::Csdn => Ok("csdn"),
        ApiProvider::Concentrate => Ok("concentrate"),
        ApiProvider::Codewhale => Ok("codewhale"),
        ApiProvider::ModelstudioTokenPlan => Ok("modelstudio_token_plan"),
        ApiProvider::ModelstudioTokenPlanAnthropic => Ok("modelstudio_token_plan_anthropic"),
        ApiProvider::ModelstudioCodingPlan => Ok("modelstudio_coding_plan"),
        ApiProvider::ModelstudioCodingPlanAnthropic => Ok("modelstudio_coding_plan_anthropic"),
        // Custom providers live under a user-chosen `[providers.<name>]` table,
        // not a fixed key. Persisting base_url through this static-key path is
        // out of scope for the #1519 constrained slice; users edit the named
        // table directly.
        ApiProvider::Custom => {
            anyhow::bail!("custom providers store base_url in their named [providers.<name>] table")
        }
    }
}

pub(crate) fn persist_custom_provider(
    config_path: Option<&Path>,
    provider_id: &str,
    base_url: &str,
    model: Option<&str>,
    api_key_env: Option<&str>,
) -> anyhow::Result<PathBuf> {
    let provider_id = normalize_custom_provider_id(provider_id)?;
    let base_url = normalize_custom_provider_base_url(base_url)?;
    let model = model.and_then(normalize_optional_custom_provider_field);
    let api_key_env = api_key_env.and_then(normalize_optional_custom_provider_field);

    let path = config_toml_path(config_path)?;
    mutate_config_document(&path, |doc| {

View on GitHub (pinned to 73e0f67d83)