Hmbown/CodeWhale · error
custom provider base URL is required
Error message
custom provider base URL is required
What it means
normalize_custom_provider_base_url rejects an empty base URL after trimming and trailing-slash removal; persist_custom_provider requires every custom provider to carry a non-empty endpoint before it is written to config.
Solutions
- Provide the provider's API endpoint (e.g. "https://api.example.com/v1") before persisting.
- Require the URL field in the caller/UI before submit.
Example fix
// before persist_custom_provider(path, "my_gateway", "", ...)?; // after persist_custom_provider(path, "my_gateway", "https://api.example.com/v1", ...)?;
Defensive patterns
Strategy: validation
Validate before calling
if url.trim().is_empty() { return Err(anyhow::anyhow!("base URL required")); } Type guard
fn has_base_url(raw: &str) -> bool { !raw.trim().trim_end_matches('/').is_empty() } Try / catch
match persist_custom_provider(path, name, &url, ...) {
Err(e) if e.to_string().contains("base URL is required") => show_form_error("URL required"),
other => other,
} Prevention
- Make the base URL field required in forms.
- Default the URL from a template like https://host/v1.
When it happens
Trigger: Calling persist_custom_provider with an empty or whitespace-only base_url string.
Common situations: A form submitted before the URL field was filled; an env var or config value that expanded to empty.
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
- custom provider base URL is invalid
- custom provider base URL must be an http(s) URL with a host
- custom provider name is required
- agent profile cannot be empty
- --base-url must use http or https
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/c5733dfbf0b2dbeb.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/config_persistence.rs:712
}
if crate::config::ApiProvider::parse(value).is_some() {
bail!("custom provider name must not shadow a built-in provider");
}
if !value
.chars()
.all(|ch| ch.is_ascii_alphanumeric() || matches!(ch, '_' | '-'))
{
bail!("custom provider name may only use letters, numbers, '-' and '_'");
}
Ok(value.to_string())
}
fn normalize_custom_provider_base_url(raw: &str) -> anyhow::Result<String> {
use anyhow::bail;
let value = raw.trim().trim_end_matches('/');
if value.is_empty() {
bail!("custom provider base URL is required");
}
let parsed = reqwest::Url::parse(value)
.map_err(|err| anyhow::anyhow!("custom provider base URL is invalid: {err}"))?;
if !matches!(parsed.scheme(), "http" | "https") || parsed.host_str().is_none() {
bail!("custom provider base URL must be an http(s) URL with a host");
}
Ok(value.to_string())
}
fn normalize_optional_custom_provider_field(raw: &str) -> Option<String> {
let value = raw.trim();
(!value.is_empty()).then(|| value.to_string())
}
pub(crate) fn persist_hotbar_bindings(
config_path: Option<&Path>,
bindings: &[codewhale_config::HotbarBindingToml],
) -> anyhow::Result<PathBuf> {View on GitHub (pinned to 73e0f67d83)