zed-industries/zed · error · anyhow::Error

cannot fetch {host:?}: loopback and IP-literal hosts can't b

Error message

cannot fetch {host:?}: loopback and IP-literal hosts can't be granted network \
             access individually. They are only reachable once unsandboxed access has been \
             granted (for example, via a terminal command that requests it).

What it means

The fetch tool refuses to grant sandboxed network access to loopback or IP-literal hosts: `HostPattern::parse` fails with the IpLiteral variant, and by design such hosts cannot be granted network access individually — they are reachable only after unsandboxed access has been granted (for example via an approved terminal command). The fetch fails before any request is made.

Source

Thrown at crates/agent/src/tools/fetch_tool.rs:205

        .port_or_known_default()
        .unwrap_or(if parsed.scheme() == "http" { 80 } else { 443 });

    http_proxy::PinnedHost::resolve(host, port).map(|_pinned| ())?;
    Ok(())
}

/// Extracts the host from a fetch URL as a [`http_proxy::HostPattern`] so it can
/// be matched against the shared network grants. Mirrors the scheme handling in
/// [`normalize_url`] (defaulting to `https://` when none is given).
fn host_pattern_for_url(url: &str) -> Result<http_proxy::HostPattern> {
    let normalized = normalize_url(url);
    let parsed =
        url::Url::parse(&normalized).with_context(|| format!("could not parse URL {url:?}"))?;
    let host = parsed
        .host_str()
        .with_context(|| format!("URL {url:?} has no host to authorize network access for"))?;
    http_proxy::HostPattern::parse(host).map_err(|error| match error {
        http_proxy::HostPatternError::IpLiteral(_) => anyhow::anyhow!(
            "cannot fetch {host:?}: loopback and IP-literal hosts can't be granted network \
             access individually. They are only reachable once unsandboxed access has been \
             granted (for example, via a terminal command that requests it)."
        ),
        error => anyhow::anyhow!("cannot authorize network access to {host:?}: {error}"),
    })
}

impl AgentTool for FetchTool {
    type Input = FetchToolInput;
    type Output = String;

    const NAME: &'static str = "fetch";

    fn kind() -> acp::ToolKind {
        acp::ToolKind::Fetch
    }

View on GitHub (pinned to bc538def45)

Solutions

  1. Use a resolvable hostname instead of the raw IP (add a hosts-file entry or DNS name), then grant access to that host.
  2. Alternatively obtain unsandboxed network access first — e.g. run and approve a terminal command that requests it — after which loopback/IP hosts are reachable.
  3. For local dev servers, expose them under a hostname the proxy can authorize.
  4. Do not attempt to bypass the check; it exists to block SSRF to loopback and metadata services.

Example fix

# before
fetch http://127.0.0.1:8080/api   # refused: IP-literal host

# after (map a hostname in /etc/hosts: 127.0.0.1 myhost.test)
fetch http://myhost.test:8080/api # hostname is individually grantable
Defensive patterns

Strategy: validation

Validate before calling

let parsed = url::Url::parse(&normalize_url(url))?;
let host = parsed.host_str().unwrap_or_default();
if host.eq_ignore_ascii_case("localhost") || host.parse::<std::net::IpAddr>().is_ok() {
    anyhow::bail!(
        "loopback/IP host {host} needs unsandboxed access — use a hostname or approve terminal network access first"
    );
}

Type guard

fn is_ip_or_loopback_host(url: &str) -> bool {
    match url::Url::parse(url) {
        Ok(parsed) => parsed
            .host_str()
            .map(|host| {
                host.eq_ignore_ascii_case("localhost")
                    || host.parse::<std::net::IpAddr>().is_ok()
            })
            .unwrap_or(false),
        Err(_) => false,
    }
}

Prevention

When it happens

Trigger: Asking the agent to fetch a URL whose host is an IP literal (127.0.0.1, 192.168.1.1, 169.254.169.254) or localhost while network access is sandboxed; `host_pattern_for_url` hits the IpLiteral error arm.

Common situations: Pointing the agent at local dev servers (http://localhost:3000); attempts to reach cloud metadata endpoints (169.254.169.254); internal services addressed by raw IP.

Related errors


AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16). Data as JSON: /api/errors/652aec3fc010bd1d. Report an issue: GitHub.