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

  1. Set the registry URL with an explicit http(s) scheme and no stray characters.
  2. Validate with a URL parser (url::Url::parse) at config load time, not at install time.
  3. 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

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


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