Hmbown/CodeWhale · warning · anyhow::Error
Pass a host like `github.com`, not a URL path
Error message
Pass a host like `github.com`, not a URL path
What it means
`normalize_host_arg` validates the host argument of the `/network allow|deny <host>` commands. Inputs starting with `http://` or `https://` are reduced to their host via `host_from_url`; any other input containing `://` (ftp://, ssh://, git://) or a `/` path component bails, because the network policy list stores bare hosts, not URLs.
Source
Thrown at crates/tui/src/commands/groups/utility/network.rs:272
if !list
.iter()
.any(|existing| normalize_host_for_compare(existing) == host)
{
list.push(host.to_string());
}
}
fn remove_host(list: &mut Vec<String>, host: &str) {
list.retain(|existing| normalize_host_for_compare(existing) != host);
}
fn normalize_host_arg(input: &str) -> anyhow::Result<String> {
let trimmed = input.trim();
let host = if trimmed.starts_with("http://") || trimmed.starts_with("https://") {
host_from_url(trimmed).context("URL must include a host")?
} else {
if trimmed.contains("://") || trimmed.contains('/') {
bail!("Pass a host like `github.com`, not a URL path");
}
trimmed.to_string()
};
let normalized = normalize_host_for_compare(&host);
if normalized.is_empty() {
bail!("host cannot be empty");
}
Ok(normalized)
}
fn normalize_host_for_compare(host: &str) -> String {
let trimmed = host.trim().trim_end_matches('.').to_ascii_lowercase();
if let Some(rest) = trimmed.strip_prefix("*.") {
format!(".{rest}")
} else {
trimmed
}View on GitHub (pinned to 0c42157ee5)
Solutions
- Pass the bare host: `/network deny github.com`.
- If you paste an http(s) URL the host is extracted automatically, but a bare host is the canonical form.
- To cover a domain and all its subdomains use wildcard syntax `*.example.com`.
- Check the argument for `/` or a non-HTTP `://` scheme before submitting.
Example fix
# before /network deny https://github.com/codewhale/codewhale # after /network deny github.com
Defensive patterns
Strategy: validation
Validate before calling
fn normalize_host_arg(input: &str) -> Option<String> {
let t = input.trim();
let host = if t.starts_with("http://") || t.starts_with("https://") {
reqwest::Url::parse(t).ok()?.host_str()?.to_ascii_lowercase()
} else {
if t.contains("://") || t.contains('/') {
return None;
}
t.to_string()
};
let host = host.trim_end_matches('.').to_ascii_lowercase();
(!host.is_empty()).then_some(host)
} Type guard
fn is_bare_host(input: &str) -> bool {
let t = input.trim();
!t.is_empty() && !t.contains('/') && !t.contains("://")
} Prevention
- Strip URLs down to the hostname in input fields before submission.
- Accept and unwrap http(s) URLs at the caller so pasted URLs still work.
- Never store URL paths or scheme prefixes in host allow/deny lists.
When it happens
Trigger: `/network deny github.com/org/repo` (URL path), `/network allow ftp://mirror.example.org`, `/network deny api.example.com/v1/entities`.
Common situations: Pasting a full git clone URL or API endpoint URL instead of the domain; using ssh:// or git:// scheme URLs, which the parser deliberately refuses (only http(s) is unwrapped).
Related errors
- host cannot be empty
- DS4 /v1/models returned HTTP {status} at {}
- DS4 /v1/models could not be reached at {} (is ds4-server run
- DS4 /v1/models timed out after 15 seconds at {}
- pipeline(): max 1000 items per call
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/36932165b25bfec2.
Report an issue: GitHub.