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
- Check the exact status in the message and open the URL in a browser/curl to confirm it is still valid.
- Fix or update the changelog URL configuration if it 404s.
- Retry later for 5xx/429 statuses; add backoff/retry around fetch_and_cache.
- 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
- Pin/verify changelog URLs and monitor them for 404s after releases
- Cache the last successful fetch so failures degrade gracefully
- Retry 5xx/429 with exponential backoff; don't retry 4xx client errors
- Check proxy/CDN behavior if 403s appear from CI networks
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
- send failed: {body}
- screen query failed: {body}
- resize failed: {body}
- wait failed: {body}
- stop failed: {body}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/d17a5d9d3423ee1a.
Report an issue: GitHub.