Hmbown/CodeWhale · error · anyhow::Error

invalid header pair '{pair}', expected name=value

Error message

invalid header pair '{pair}', expected name=value

What it means

parse_http_headers splits a comma-separated raw string on '=' to build the extra-headers map sent to model API requests. A non-empty pair that contains no '=' at all (split_once('=') returns None) bails with 'invalid header pair \'{pair}\', expected name=value'. Empty segments between commas are skipped, so only genuinely malformed pairs trigger it.

Source

Thrown at crates/tui/src/config.rs:9958

    let deepseek_domains = ["api.deepseek.com", "api.deepseeki.com"];
    if deepseek_domains
        .iter()
        .any(|domain| trimmed.contains(domain))
    {
        return trimmed.trim_end_matches("/v1").to_string();
    }
    trimmed.to_string()
}

fn parse_http_headers(raw: &str) -> Result<HashMap<String, String>> {
    let mut headers = HashMap::new();
    for pair in raw.trim().split(',') {
        let pair = pair.trim();
        if pair.is_empty() {
            continue;
        }
        let Some((name, value)) = pair.split_once('=') else {
            anyhow::bail!("invalid header pair '{pair}', expected name=value");
        };
        let name = name.trim();
        let value = value.trim();
        if name.is_empty() {
            anyhow::bail!("header name cannot be empty");
        }
        if value.is_empty() {
            continue;
        }
        headers.insert(name.to_string(), value.to_string());
    }
    Ok(headers)
}

fn apply_profile(config: ConfigFile, profile: Option<&str>) -> Result<Config> {
    if let Some(profile_name) = profile {
        let profiles = config.profiles.as_ref();
        match profiles.and_then(|profiles| profiles.get(profile_name)) {

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Convert each header to name=value form: 'Authorization=Bearer tok' instead of 'Authorization: Bearer tok'
  2. Ensure every comma-separated segment either is empty or contains exactly a name=value pair
  3. For values containing commas, check whether the surface accepts repeated flags or a config table instead of one raw string

Example fix

# before
$ codewhale --http-headers "X-Trace-Id: abc123"
# error: invalid header pair 'X-Trace-Id: abc123', expected name=value

# after
$ codewhale --http-headers "X-Trace-Id=abc123"
Defensive patterns

Strategy: validation

Validate before calling

// Validate a raw header string with the same rule before passing it in:
fn http_headers_string_ok(raw: &str) -> bool {
    raw.trim().split(',').all(|pair| {
        let pair = pair.trim();
        pair.is_empty() || pair.split_once('=').is_some()
    })
}
assert!(http_headers_string_ok(&raw), "every header pair must be name=value");

Type guard

fn is_valid_header_pair(pair: &str) -> bool {
    let pair = pair.trim();
    pair.is_empty() || pair.split_once('=').is_some_and(|(n, _)| !n.trim().is_empty())
}

Try / catch

match parse_http_headers(&raw) {
    Err(e) if e.to_string().starts_with("invalid header pair") => {
        // show the offending pair, hint 'name=value not name: value', and re-prompt
    }
    other => other?,
}

Prevention

When it happens

Trigger: Passing --http-headers (or the equivalent config/setting) with a segment like 'Authorization: Bearer tok' (colon syntax), a bare token such as 'x-trace', or a value containing spaces that split off a fragment without '='.

Common situations: Copying a curl-style '-H "Name: value"' header into Codewhale's name=value syntax; trailing punctuation after a pair; values containing '=' are fine but values with commas force a split that can orphan text.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/f95f04382edf268e. Report an issue: GitHub.