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(®.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
- Convert scp syntax to https: git@github.com:org/repo.git -> https://github.com/org/repo.git
- Ensure the URL has an explicit scheme (https:// or file://) and no raw spaces
- 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
- Never paste `git@host:path` clone strings; translate them to https:// first
- Always include the scheme; quote URLs in TOML to avoid whitespace artifacts
- Test candidate URLs with Url::parse in a scratch test before committing config
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
- skills.extra_registries[{i}].name '{}' is invalid; use only
- registry '{registry_name}' uses unsupported kind '{}'; only
- skill '{skill_name}' not found in registry '{registry_name}'
- Refusing to transmit sensitive data over non-HTTPS URL: URL
- broker_url must start with 'mqtt://' or 'mqtts://', got: {}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/e2a8948e3344fbfc.
Report an issue: GitHub.