zeroclaw-labs/zeroclaw · error

skills.extra_registries[{}].url is not a valid URL: {e}

Error message

skills.extra_registries[{}].url is not a valid URL: {e}

What it means

Config::validate() reports this when reqwest::Url::parse itself fails on a skills.extra_registries[].url value, with the underlying parse error ({e}) included. Unlike the scheme check, this means the string is not a parseable absolute URL at all: missing scheme, spaces, control characters, or scp-style "git@host:path" syntax that is not a real URL.

Source

Thrown at crates/zeroclaw-config/src/schema.rs:22000

                        "skills.extra_registries[{}].url must not be empty",
                        reg.name
                    );
                }
                if reg.kind != ExternalRegistryKind::Git {
                    anyhow::bail!(
                        "skills.extra_registries[{}].kind must be 'git' (got '{}'); other protocols are not yet supported",
                        reg.name,
                        reg.kind
                    );
                }
                match reqwest::Url::parse(&reg.url) {
                    Ok(u) if matches!(u.scheme(), "http" | "https" | "file") => {}
                    Ok(u) => anyhow::bail!(
                        "skills.extra_registries[{}].url scheme '{}' is unsupported (use http, https, or file)",
                        reg.name,
                        u.scheme()
                    ),
                    Err(e) => anyhow::bail!(
                        "skills.extra_registries[{}].url is not a valid URL: {e}",
                        reg.name
                    ),
                }
            }
        }

        // Notion
        if self.notion.enabled {
            if self.notion.database_id.trim().is_empty() {
                anyhow::bail!("notion.database_id must not be empty when notion.enabled = true");
            }
            if self.notion.poll_interval_secs == 0 {
                validation_bail!(
                    InvalidNumericRange,
                    "notion.poll_interval_secs",
                    "notion.poll_interval_secs must be greater than 0"
                );

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Convert scp syntax to https: git@github.com:org/repo.git -> https://github.com/org/repo.git
  2. Ensure the URL has an explicit scheme (https:// or file://) and no raw spaces
  3. Run the value through a URL parse (e.g. `python -c 'from urllib.parse import urlparse...'` or reqwest in a scratch test) before shipping the config

Example fix

# before
[[skills.extra_registries]]
name = "team"
url = "git@github.com:acme/skills.git"

# after
[[skills.extra_registries]]
name = "team"
url = "https://github.com/acme/skills.git"
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: the string must be a parseable absolute URL
fn registry_url_parses(url: &str) -> bool {
    reqwest::Url::parse(url).is_ok()
}

Type guard

fn registry_url_parses(url: &str) -> bool {
    reqwest::Url::parse(url.trim()).is_ok()
}

Try / catch

match config.validate() {
    Ok(()) => {}
    Err(e) if e.to_string().contains("is not a valid URL") => {
        // e echoes the parse error; most often scp syntax 'git@host:path' -> use https://host/...
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: url = "git@git.example.com:team/skills.git" (scp syntax, no scheme), url = "not a url", or url with unencoded spaces/quotes in a registry block failing parse during Config::validate().

Common situations: Pasting the GitHub/GitLab SSH clone string (git@github.com:org/repo.git) which is scp syntax, not a URL; forgetting the scheme; values corrupted by quotes/smart quotes from documentation copy-paste.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/e2a8948e3344fbfc. Report an issue: GitHub.