{"record":{"id":"fa03069a8e5ba941","repo":"NousResearch/hermes-agent","slug":"failed-to-download-http-from","errorCode":null,"errorMessage":"Failed to download {}: HTTP {} from {}","messagePattern":"Failed to download (.+?): HTTP (.+?) from (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"apps/bootstrap-installer/src-tauri/src/install_script.rs","lineNumber":358,"sourceCode":"            .extension()\n            .and_then(|s| s.to_str())\n            .unwrap_or(\"tmp\");\n        format!(\"{ext}.tmp\")\n    });\n\n    let response = reqwest::Client::builder()\n        .connect_timeout(std::time::Duration::from_secs(10))\n        .timeout(std::time::Duration::from_secs(60))\n        .build()\n        .context(\"building download client\")?\n        .get(&url)\n        .header(\"User-Agent\", \"hermes-setup/0.0.1\")\n        .send()\n        .await\n        .with_context(|| format!(\"GET {url}\"))?;\n\n    if !response.status().is_success() {\n        return Err(anyhow!(\n            \"Failed to download {}: HTTP {} from {}\",\n            kind.filename(),\n            response.status(),\n            url\n        ));\n    }\n\n    let bytes = response\n        .bytes()\n        .await\n        .with_context(|| format!(\"reading body of {url}\"))?;\n    let bytes = prepare_cached_script_bytes(kind, &bytes);\n\n    let mut file = tokio::fs::File::create(&tmp_path)\n        .await\n        .with_context(|| format!(\"creating temp file {}\", tmp_path.display()))?;\n    file.write_all(&bytes)\n        .await","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/apps/bootstrap-installer/src-tauri/src/install_script.rs#L340-L376","documentation":"Raised by the network fallback in install-script resolution: the HTTP GET for install-main.ps1 (or the kind-specific file) returned a non-2xx status. The client already applied a 10s connect / 60s overall timeout and a hermes-setup User-Agent; only the response status check fails here — transport errors surface as the `GET {url}` context error instead.","triggerScenarios":"Fetching the script URL when the pinned commit/branch does not exist upstream (404), GitHub is rate-limiting or serving a 5xx, a proxy in the middle returns 407/502, or the branch was renamed after the installer was built (410/404).","commonSituations":"Corporate proxies intercepting raw.githubusercontent.com; GitHub API rate limits on CI runners; using a stale installer binary pinned to a branch that was since deleted; typosquat URL rewrite by DNS-level filtering.","solutions":["Retry — transient 5xx/rate-limit statuses usually clear; the branch-pin path already avoids poisoned caches on retry.","curl -I the exact URL from the error message to see the status and whether a proxy is intercepting.","If the branch was renamed/deleted, rebuild or re-run with a pin to an existing commit SHA.","Whitelist the script host in proxy/antivirus config, or configure the proxy env for the installer process."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Retry with backoff on transient statuses; branch pins are always re-fetched so a poisoned cache can't stick.\nasync fn fetch_script_with_retry(url: &str, kind: Kind) -> Result<bytes::Bytes> {\n    let mut attempt = 0;\n    loop {\n        attempt += 1;\n        match download(url, kind).await {\n            Ok(b) => return Ok(b),\n            Err(e) if attempt < 3 && is_retryable(&e) => {\n                tokio::time::sleep(std::time::Duration::from_secs(2u64.pow(attempt))).await;\n            }\n            Err(e) => return Err(e),\n        }\n    }\n}\n\nfn is_retryable(e: &anyhow::Error) -> bool {\n    let s = format!(\"{e:#}\");\n    s.contains(\"HTTP 5\") || s.contains(\"HTTP 429\") || s.contains(\"timed out\")\n}","preventionTips":["Pin releases to commit SHAs so a renamed/deleted branch can't 404 an old installer.","Verify network egress to the script host (and proxy config) before running the installer on locked-down machines.","Keep the branch-pin refresh behavior intact so retries never serve a poisoned cached script."],"tags":["network","http","bootstrap-installer","github"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}