zeroclaw-labs/zeroclaw · error

URL has no host: {}

Error message

URL has no host: {}

What it means

After parsing, browser_delegate requires a non-empty host component from the parsed URL. URLs that parse but carry no host — 'http:///path', 'https://?q=1' — fail here. The host is required because the domain allow/block checks that follow operate on it.

Source

Thrown at crates/zeroclaw-tools/src/browser_delegate.rs:96

                    .with_attrs(::serde_json::json!({
                        "url": url,
                        "error": format!("{}", e),
                    })),
                "browser_delegate: invalid URL"
            );
            anyhow::Error::msg(format!("invalid URL '{}': {}", url, e))
        })?;

        // Only allow http/https schemes
        let scheme = parsed.scheme();
        if scheme != "http" && scheme != "https" {
            anyhow::bail!("unsupported URL scheme: {}", scheme);
        }

        let domain = parsed.host_str().unwrap_or("").to_string();

        if domain.is_empty() {
            anyhow::bail!("URL has no host: {}", url);
        }

        // Check blocked domains first (deny takes precedence)
        for blocked in &self.config.blocked_domains {
            if domain_matches(&domain, blocked) {
                anyhow::bail!("domain '{}' is blocked by browser_delegate policy", domain);
            }
        }

        // If allowed_domains is non-empty, it acts as an allowlist
        if !self.config.allowed_domains.is_empty() {
            let allowed = self
                .config
                .allowed_domains
                .iter()
                .any(|d| domain_matches(&domain, d));
            if !allowed {
                anyhow::bail!(

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Fix the URL to include an explicit host: https://example.com/health
  2. Assemble URLs with a builder (reqwest::Url, url::Url::join) rather than string concatenation
  3. Pre-check candidate URLs with url.parse::<Url>() and host_str().is_some() before submitting the task

Example fix

// before
"http:///health"
// after
"https://example.com/health"
Defensive patterns

Strategy: validation

Validate before calling

let parsed: reqwest::Url = candidate.parse()?;
if parsed.host_str().map(str::is_empty).unwrap_or(true) {
    return Err(format!("URL has no host: {candidate}"));
}

Try / catch

match delegate.execute(args).await {
    Ok(res) if res.success => { /* ... */ }
    Ok(res) => {
        if res.error.as_deref().unwrap_or_default().contains("no host") {
            // fix URL construction; host is missing
        }
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A task URL like "http:///health" (triple slash), "https://?next=1", or a malformed paste where the domain was dropped.

Common situations: String-concatenation bugs that lose the host between scheme and path; copy-paste truncation; model-generated URLs that omit the domain.

Related errors


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