Hmbown/CodeWhale · error

base URL cannot be empty

Error message

base URL cannot be empty

What it means

save_provider_base_url_for_identity trims and slash-trims the guided-setup endpoint and rejects an empty value; a provider's [providers.<name>] base_url must be a non-empty URL, and the narrow writer never touches the root base_url.

Solutions

  1. Pass a complete base URL (e.g. `https://api.example.com/v1`) to the routine
  2. Validate the URL is non-empty and parses before calling save
  3. To return to a provider's default endpoint, remove the override instead of saving an empty value

Example fix

// before
save_provider_base_url_for_identity(&identity, &cfg, "")?;
// after
let url = input.trim();
anyhow::ensure!(!url.is_empty(), "base URL required");
save_provider_base_url_for_identity(&identity, &cfg, url)?;
Defensive patterns

Strategy: validation

Validate before calling

let url = base_url.trim();
if url.is_empty() { return Err(anyhow::anyhow!("base URL required")); }

Try / catch

if let Err(e) = save_provider_base_url_for_identity(&identity, &cfg, u) {
    if e.to_string().contains("base URL cannot be empty") {
        // clear the override via the delete path instead
    }
}

Prevention

When it happens

Trigger: Calling `save_provider_base_url_for_identity` with `base_url` empty or whitespace-only after trim.

Common situations: User cleared the base-URL field and saved; migration imported a config with an empty URL; script variable unset before the call.

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/db453acc2c12bdb8. Report an issue: GitHub.

Appendix: source

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

        identity.provider,
        identity.persisted_id().unwrap_or(&identity.key),
        model,
    )
}

/// Persist a guided-setup endpoint choice into the provider's own
/// `[providers.<name>] base_url` (#4526).
///
/// Deliberately narrow: it never touches the root `base_url`, another
/// provider's table, or any other key, so a billing-route choice cannot
/// repoint an unrelated route.
pub(crate) fn save_provider_base_url_for_identity(
    identity: &ProviderIdentity,
    _route_config: &Config,
    base_url: &str,
) -> Result<PathBuf> {
    let base_url = base_url.trim();
    anyhow::ensure!(!base_url.is_empty(), "base URL cannot be empty");
    let config_path = try_default_config_path()
        .context("Failed to resolve config path for provider base URL.")?;
    ensure_parent_dir(&config_path)?;
    let key_inside = if identity.provider == ApiProvider::Custom {
        let key = identity.key.trim();
        anyhow::ensure!(!key.is_empty(), "custom provider id cannot be empty");
        key
    } else {
        provider_config_key(identity.provider).context("provider base URL table")?
    };
    crate::config_persistence::mutate_config_document(&config_path, |doc| {
        crate::config_persistence::set_document_value(
            doc,
            &["providers", key_inside, "base_url"],
            base_url,
        )
    })
    .with_context(|| format!("Failed to write config to {}", config_path.display()))?;

View on GitHub (pinned to 73e0f67d83)