zeroclaw-labs/zeroclaw · warning · anyhow::Error
Only http:// and https:// URLs are allowed
Error message
Only http:// and https:// URLs are allowed
What it means
validate_text_browser_url only permits URLs whose string form starts with http:// or https://. Any other scheme — file://, ftp://, data:, gopher://, about:, or an uppercase HTTP:// — fails this prefix check before reqwest::Url::parse is even attempted.
Source
Thrown at crates/zeroclaw-tools/src/text_browser.rs:226
}
fn validate_text_browser_url(
url: &str,
allowed_private_hosts: &[String],
validate_dns: impl FnOnce(&str, bool) -> anyhow::Result<()>,
) -> anyhow::Result<String> {
let url = url.trim();
if url.is_empty() {
anyhow::bail!("URL cannot be empty");
}
if url.chars().any(char::is_whitespace) {
anyhow::bail!("URL cannot contain whitespace");
}
if !url.starts_with("http://") && !url.starts_with("https://") {
anyhow::bail!("Only http:// and https:// URLs are allowed");
}
let parsed = reqwest::Url::parse(url)
.map_err(|e| anyhow::Error::msg(format!("Invalid URL format: {e}")))?;
if !parsed.username().is_empty() || parsed.password().is_some() {
anyhow::bail!("URL userinfo is not allowed");
}
let host_str = parsed
.host_str()
.ok_or_else(|| anyhow::Error::msg("URL must include a host"))?;
let bare_host = host_str.trim_start_matches('[').trim_end_matches(']');
let is_ipv6 = bare_host.parse::<std::net::Ipv6Addr>().is_ok();
let (host, display_host) = if is_ipv6 {
let bare = bare_host.parse::<std::net::Ipv6Addr>().unwrap().to_string();
(bare.clone(), format!("[{bare}]"))View on GitHub (pinned to 88bb9c8533)
Solutions
- Use an http:// or https:// URL
- Normalize the scheme to lowercase before calling the tool
- For local file reading, use the dedicated file tools — the text browser intentionally refuses other schemes
Example fix
// before
{"url":"HTTP://Example.COM/docs"}
// after
{"url":"http://example.com/docs"} Defensive patterns
Strategy: validation
Validate before calling
let normalized = url.trim().to_ascii_lowercase();
if !(normalized.starts_with("http://") || normalized.starts_with("https://")) { /* reject */ } Type guard
fn is_http_url(u: &str) -> bool {
let u = u.trim().to_ascii_lowercase();
u.starts_with("http://") || u.starts_with("https://")
} Try / catch
Err(e) if e.to_string().starts_with("Only http://") => {
// non-http schemes are unsupported by design: reject the input, do not retry
} Prevention
- Lowercase the scheme before validation to avoid case-sensitive surprises
- Route local-file needs to file tools, never through the text browser
- Validate schemes at input ingestion, not at fetch time
When it happens
Trigger: Passing "ftp://mirror.example.com/file", "file:///etc/passwd", "data:text/html,...", or "HTTP://EXAMPLE.COM" (the check is case-sensitive on the scheme); relative URLs like "/docs/index.html" also fail.
Common situations: Users pasting links from file managers or older docs that use ftp; attempts to read local files through the browser tool (blocked by design); uppercase schemes from auto-generated URLs that were never normalized to lowercase.
Related errors
- Only http:// and https:// URLs are allowed
- Custom model_provider `{prefix}:<url>` requires a URL beginn
- OpenAI Codex endpoint override must use http:// or https://
- unsupported URL scheme: {}
- Only http:// or https:// URLs are allowed
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/206c27332794a805.
Report an issue: GitHub.