Hmbown/CodeWhale · error
invalid registry url: {registry_url}
Error message
invalid registry url: {registry_url} What it means
fetch_registry extracts a host from the configured registry URL before consulting the network policy; when host_from_url returns None (scheme missing or URL unparseable) it bails immediately. This keeps the policy engine from ever matching against a hostless URL, and it fails before any request is made.
Source
Thrown at crates/tui/src/skills/install.rs:543
if !target.join(INSTALLED_FROM_MARKER).exists() {
return Err(InstallError::NotInstalledHere(name.to_string()).into());
}
let content_digest = super::package_digest::compute_package_digest(&target)
.with_context(|| format!("cannot compute content digest for {}", target.display()))?;
write_trust_v2(&target, &content_digest)?;
Ok(())
}
/// Fetch the curated registry and return the parsed entries.
///
/// Honours `network` (skipping the call entirely on Deny / Prompt).
pub async fn fetch_registry(
network: &NetworkPolicy,
registry_url: &str,
) -> Result<RegistryFetchResult> {
let host = match host_from_url(registry_url) {
Some(host) => host,
None => bail!("invalid registry url: {registry_url}"),
};
match network.decide(&host) {
Decision::Allow => {}
Decision::Deny => return Ok(RegistryFetchResult::Denied(host)),
Decision::Prompt => return Ok(RegistryFetchResult::NeedsApproval(host)),
}
let body = reqwest_client()
.get(registry_url)
.send()
.await
.with_context(|| format!("failed to fetch registry {registry_url}"))?
.error_for_status()
.with_context(|| format!("registry {registry_url} returned an error status"))?
.text()
.await
.with_context(|| format!("failed to read registry body from {registry_url}"))?;
let parsed: RegistryDocument = serde_json::from_str(&body)
.with_context(|| format!("failed to parse registry json from {registry_url}"))?;View on GitHub (pinned to 0c42157ee5)
Solutions
- Set the registry URL with an explicit http(s) scheme and no stray characters.
- Validate with a URL parser (url::Url::parse) at config load time, not at install time.
- If the registry moved, update the setting; do not rely on redirects at this layer.
Example fix
# before registry = "skills.example.com/registry.json" # after registry = "https://skills.example.com/registry.json"
Defensive patterns
Strategy: validation
Validate before calling
fn registry_url_ok(url: &str) -> bool {
url::Url::parse(url)
.ok()
.and_then(|u| u.host_str().map(|h| !h.is_empty()))
.unwrap_or(false)
} Prevention
- Validate the registry URL at config load time with url::Url::parse.
- Always include the http(s) scheme; a bare host will not parse to a host-based URL here.
- Add a config lint that rejects scheme-less URLs before first use.
When it happens
Trigger: A registry_url configuration like 'skills.example.com/registry.json' (no scheme), 'ftp://...' (unsupported scheme), or a malformed string with spaces. Any install or registry-list flow that reaches fetch_registry with that configuration fails here.
Common situations: Hand-edited config dropping the 'https://', environment variables carrying a bare host, and copy-paste truncation of the URL.
Related errors
- invalid download url: {url}
- skill '{name}' was imported locally (spec '{}') and cannot b
- registry source '{name}' cannot be fetched as a plain tarbal
- registry entry for '{name}' must not point to another regist
- context_window must be greater than 0
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/055d5a846fccb300.
Report an issue: GitHub.