xai-org/grok-build · error

HTTP {}

Error message

HTTP {}

What it means

fetch_blocking performs a synchronous HTTP GET (used by fetch_json / fetch_and_cache for changelog retrieval) and bails with "HTTP {status}" whenever the response status is not a success (2xx). It surfaces the raw status code, e.g. "HTTP 404 Not Found" or "HTTP 503 Service Unavailable".

Source

Thrown at crates/codegen/xai-grok-shell-base/src/util/changelog.rs:216

/// Strips `**bold**` and backtick formatting from each description and returns at most `max` entries.
/// Entries with an empty description (from tolerant deserialization) are skipped.
pub fn bullets_from_entries(entries: &[ChangelogEntry], max: usize) -> Vec<String> {
    entries
        .iter()
        .filter(|e| !e.description.is_empty())
        .take(max)
        .map(|e| strip_markdown_inline(&e.description))
        .collect()
}

/// Blocking HTTP fetch.
/// Callers (`std::thread::scope` threads) are already off the tokio runtime, so no extra thread spawn is needed.
fn fetch_blocking(url: &str) -> anyhow::Result<String> {
    let client =
        xai_grok_extra_ca::build_blocking_reqwest_client(|builder| builder.timeout(FETCH_TIMEOUT))?;
    let resp = client.get(url).send()?;
    if !resp.status().is_success() {
        anyhow::bail!("HTTP {}", resp.status());
    }
    Ok(resp.text()?)
}

#[cfg(test)]
mod tests {
    use super::*;

    /// Build a manager pointing at `home` directly, bypassing the global `$GROK_HOME` env so tests never race the parallel harness.
    fn manager_for(home: &std::path::Path) -> ChangelogManager {
        ChangelogManager {
            md_cache: home.join("CHANGELOG.md"),
            json_cache: home.join("CHANGELOG.json"),
        }
    }

    #[test]
    fn offline_mode_reads_seeded_disk_cache_only() {

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Check the exact status in the message and open the URL in a browser/curl to confirm it is still valid.
  2. Fix or update the changelog URL configuration if it 404s.
  3. Retry later for 5xx/429 statuses; add backoff/retry around fetch_and_cache.
  4. Verify no corporate proxy or firewall is rewriting/blocking the request (403).

Example fix

// before
let body = fetch_json(url)?;
// after
match fetch_json(url) {
    Ok(body) => body,
    Err(e) if e.to_string().contains("HTTP 4") || e.to_string().contains("HTTP 5") => {
        eprintln!("changelog unavailable ({e}); using cached copy");
        read_cached_changelog()
    }
    Err(e) => return Err(e),
}
Defensive patterns

Strategy: retry

Try / catch

match fetch_json(url) {
    Ok(v) => v,
    Err(e) => {
        let msg = e.to_string();
        if msg.starts_with("HTTP 5") || msg == "HTTP 429" {
            // transient: retry with backoff, then fall back to cache
            retry_with_backoff(3, || fetch_json(url)).unwrap_or_else(|_| cached_changelog())
        } else if msg.starts_with("HTTP 4") {
            cached_changelog() // permanent: skip fetch
        } else {
            Default::default()
        }
    }
}

Prevention

When it happens

Trigger: Any changelog URL request returning a non-2xx status: 404 (URL moved/renamed), 403 (blocked/geo/rate-limited), 5xx (server outage); raised inside fetch_blocking, propagating to fetch_json and fetch_and_cache.

Common situations: The changelog hosting URL changed or the release asset was deleted; corporate proxies/CDNs returning 403; GitHub raw content rate-limiting (403/429); the server being temporarily down (5xx).

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/d17a5d9d3423ee1a. Report an issue: GitHub.