{"record":{"id":"b526c6943acac348","repo":"Hmbown/CodeWhale","slug":"host-cannot-be-empty","errorCode":null,"errorMessage":"host cannot be empty","messagePattern":"host cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/tui/src/commands/groups/utility/network.rs","lineNumber":284,"sourceCode":"\nfn remove_host(list: &mut Vec<String>, host: &str) {\n    list.retain(|existing| normalize_host_for_compare(existing) != host);\n}\n\nfn normalize_host_arg(input: &str) -> anyhow::Result<String> {\n    let trimmed = input.trim();\n    let host = if trimmed.starts_with(\"http://\") || trimmed.starts_with(\"https://\") {\n        host_from_url(trimmed).context(\"URL must include a host\")?\n    } else {\n        if trimmed.contains(\"://\") || trimmed.contains('/') {\n            bail!(\"Pass a host like `github.com`, not a URL path\");\n        }\n        trimmed.to_string()\n    };\n\n    let normalized = normalize_host_for_compare(&host);\n    if normalized.is_empty() {\n        bail!(\"host cannot be empty\");\n    }\n    Ok(normalized)\n}\n\n/// Extract the host portion of a URL, lowercased (leaf `reqwest::Url` parse;\n/// no TUI helper dependency).\nfn host_from_url(url: &str) -> Option<String> {\n    let parsed = reqwest::Url::parse(url.trim()).ok()?;\n    parsed.host_str().map(str::to_ascii_lowercase)\n}\n\nfn normalize_host_for_compare(host: &str) -> String {\n    let trimmed = host.trim().trim_end_matches('.').to_ascii_lowercase();\n    if let Some(rest) = trimmed.strip_prefix(\"*.\") {\n        format!(\".{rest}\")\n    } else {\n        trimmed\n    }","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/commands/groups/utility/network.rs#L266-L302","documentation":"After normalization (URL host extraction, lowercasing, trimming), normalize_host_arg bails when the resulting host is empty. This guards against arguments like empty strings, whitespace, `http://` with no host, or inputs that reduce to nothing after comparison normalization.","triggerScenarios":"`/network allow` with an empty/whitespace-only quoted arg, or `/network allow https://` where the URL has no host part.","commonSituations":"Scripted invocations passing an unset variable (empty string); pasting a bare scheme; trailing-slash-only input.","solutions":["Provide a real hostname, e.g. `/network allow api.example.com`","If using a URL, ensure it includes a host before the path","Check shell variables for empty values before interpolating into the command"],"exampleFix":"// before\nHOST=\"\"; /network allow \"$HOST\"\n// after\nHOST=\"api.example.com\"; /network allow \"$HOST\"","handlingStrategy":"validation","validationCode":"function hostOf(input) {\n  let t = input.trim();\n  if (/^https?:\\/\\//.test(t)) t = new URL(t).hostname;\n  t = t.trim().toLowerCase();\n  if (!t) throw new Error('host cannot be empty');\n  return t;\n}","typeGuard":"const hasHost = (s: string): boolean => {\n  try { return new URL(s.includes('://') ? s : 'https://' + s).hostname.length > 0; }\n  catch { return false; }\n};","tryCatchPattern":"try { run(`/network allow ${arg}`); } catch (e) { if (String(e).includes('host cannot be empty')) console.log('Provide a non-empty hostname'); }","preventionTips":["Check that interpolated shell variables are non-empty","A URL argument must include a host (not just `https://`)","Trim whitespace before passing"],"tags":["cli","empty-value","validation"],"backgroundTag":"empty-required-field","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}