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
- Use a resolvable hostname instead of the raw IP (add a hosts-file entry or DNS name), then grant access to that host.
- Alternatively obtain unsandboxed network access first — e.g. run and approve a terminal command that requests it — after which loopback/IP hosts are reachable.
- For local dev servers, expose them under a hostname the proxy can authorize.
- 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
- Expose local services under hostnames (e.g. a hosts-file entry) instead of raw IPs.
- Grant unsandboxed network access via an approved terminal command when loopback is truly required.
- Never try to bypass the check — it blocks SSRF to loopback and metadata endpoints.
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
- refusing to follow redirect to non-HTTP(S) URL {target}
- cannot authorize network access to {host:?}: {error}
- archive links are not supported: {member.name}
- archive member escapes destination: {member.name}
- Slack webhook returned {response.status_code}: {response.tex
AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16).
Data as JSON: /api/errors/652aec3fc010bd1d.
Report an issue: GitHub.