zeroclaw-labs/zeroclaw · error

HTTP {} downloading datasheet from {url}

Error message

HTTP {} downloading datasheet from {url}

What it means

`download_datasheet` GETs a component datasheet URL with reqwest (30s timeout, ZeroClaw user agent) and bails on any non-2xx status, embedding the HTTP status and URL. The status code is the diagnosis: 404 means the datasheet moved or the URL is wrong, 403 usually means bot/hotlink blocking, 5xx means vendor-side outage. DNS and timeout failures surface as different errors from `send()`, so this one is strictly an HTTP response status problem.

Source

Thrown at crates/zeroclaw-hardware/src/datasheet.rs:70

    /// Returns the path to the saved file.
    pub async fn download_datasheet(
        &self,
        url: &str,
        device_name: &str,
    ) -> anyhow::Result<PathBuf> {
        std::fs::create_dir_all(&self.datasheet_dir)?;

        let filename = format!("{}.pdf", device_name.to_lowercase().replace(' ', "_"));
        let dest = self.datasheet_dir.join(&filename);

        let client = reqwest::Client::builder()
            .user_agent("ZeroClaw/0.1 (datasheet downloader)")
            .timeout(std::time::Duration::from_secs(30))
            .build()?;

        let response = client.get(url).send().await?;
        if !response.status().is_success() {
            anyhow::bail!(
                "HTTP {} downloading datasheet from {url}",
                response.status()
            );
        }
        let bytes = response.bytes().await?;
        std::fs::write(&dest, &bytes)?;

        ::zeroclaw_log::record!(
            INFO,
            ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note).with_attrs(
                ::serde_json::json!({"device": device_name, "path": dest.display().to_string()})
            ),
            "datasheet downloaded"
        );
        Ok(dest)
    }

    /// List all locally cached datasheet filenames.

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Read the status in the message: for 404, find the datasheet's current URL on the vendor's product page and update the tool input
  2. For 403, download the file manually in a browser and point the tool at a local or mirrored copy
  3. Retry later for 5xx — the outage is on the vendor's side

Example fix

// before
download_datasheet("https://vendor.com/old/lm741.pdf").await?;
// after — canonical URL from the vendor's current product page
download_datasheet("https://www.ti.com/lit/ds/symlink/lm741.pdf").await?;
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight the URL cheaply before downloading:
let resp = client.head(url).send().await?;
if !resp.status().is_success() {
    anyhow::bail!("datasheet URL unreachable ({}): {url}", resp.status());
}

Try / catch

let mut attempt = 0;
loop {
    match download_datasheet(url, &dest).await {
        Ok(_) => break,
        Err(e) if attempt < 2 && e.to_string().contains("HTTP 5") => {
            attempt += 1;
            tokio::time::sleep(std::time::Duration::from_secs(2u64.pow(attempt))).await;
        }
        Err(e) => return Err(e), // 404/403 are permanent — do not retry
    }
}

Prevention

When it happens

Trigger: Executing the datasheet tool with a vendor URL that 404s after the manufacturer reorganized their site; a 403 from portals that block non-browser user agents; 5xx during vendor downtime.

Common situations: Stale hardcoded datasheet URLs in tool configuration; datasheet portals behind bot protection; typos in the URL handed to the tool.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/4ad9e45980552963. Report an issue: GitHub.