Hmbown/CodeWhale · warning

host cannot be empty

Error message

host cannot be empty

What it means

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.

Solutions

  1. Provide a real hostname, e.g. `/network allow api.example.com`
  2. If using a URL, ensure it includes a host before the path
  3. Check shell variables for empty values before interpolating into the command

Example fix

// before
HOST=""; /network allow "$HOST"
// after
HOST="api.example.com"; /network allow "$HOST"
Defensive patterns

Strategy: validation

Validate before calling

function hostOf(input) {
  let t = input.trim();
  if (/^https?:\/\//.test(t)) t = new URL(t).hostname;
  t = t.trim().toLowerCase();
  if (!t) throw new Error('host cannot be empty');
  return t;
}

Type guard

const hasHost = (s: string): boolean => {
  try { return new URL(s.includes('://') ? s : 'https://' + s).hostname.length > 0; }
  catch { return false; }
};

Try / catch

try { run(`/network allow ${arg}`); } catch (e) { if (String(e).includes('host cannot be empty')) console.log('Provide a non-empty hostname'); }

Prevention

When it happens

Trigger: `/network allow` with an empty/whitespace-only quoted arg, or `/network allow https://` where the URL has no host part.

Common situations: Scripted invocations passing an unset variable (empty string); pasting a bare scheme; trailing-slash-only input.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/b526c6943acac348. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/commands/groups/utility/network.rs:284

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)
}

/// Extract the host portion of a URL, lowercased (leaf `reqwest::Url` parse;
/// no TUI helper dependency).
fn host_from_url(url: &str) -> Option<String> {
    let parsed = reqwest::Url::parse(url.trim()).ok()?;
    parsed.host_str().map(str::to_ascii_lowercase)
}

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 73e0f67d83)