rust-lang/rust · error · anyhow::Error

Cannot fetch metrics from {url}: {} {}

Error message

Cannot fetch metrics from {url}: {}
{}

What it means

Thrown by download_job_metrics when the HTTP GET to the ci-artifacts.rust-lang.org metrics URL returns a non-success status code. The message includes the URL, the HTTP status, and the response body text, so the upstream error (e.g. 404 for a missing artifact, 403 for access denied) is visible.

Source

Thrown at src/ci/citool/src/metrics.rs:92

    Ok(jobs)
}

pub fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result<JsonRoot> {
    // Best effort cache to speed-up local re-executions of citool
    let cache_path = PathBuf::from(".citool-cache").join(sha).join(format!("{job_name}.json"));
    if cache_path.is_file() {
        if let Ok(metrics) = std::fs::read_to_string(&cache_path)
            .map_err(|err| err.into())
            .and_then(|data| anyhow::Ok::<JsonRoot>(serde_json::from_str::<JsonRoot>(&data)?))
        {
            return Ok(metrics);
        }
    }

    let url = get_metrics_url(job_name, sha);
    let mut response = ureq::get(&url).call()?;
    if !response.status().is_success() {
        return Err(anyhow::anyhow!(
            "Cannot fetch metrics from {url}: {}\n{}",
            response.status(),
            response.body_mut().read_to_string()?
        ));
    }
    let data: JsonRoot = response
        .body_mut()
        .read_json()
        .with_context(|| anyhow::anyhow!("cannot deserialize metrics from {url}"))?;

    if let Ok(_) = std::fs::create_dir_all(cache_path.parent().unwrap()) {
        if let Ok(data) = serde_json::to_string(&data) {
            let _ = std::fs::write(cache_path, data);
        }
    }

    Ok(data)
}

View on GitHub (pinned to 7088e4b63a)

Solutions

  1. Verify the SHA exists on the rust-lang/rust remote and that its CI run completed and published artifacts.
  2. Confirm the job_name matches an actual CI job (see the available-jobs list).
  3. Delete the .citool-cache directory to rule out a stale/partial cache, then retry.
  4. If the status is 5xx, retry after the ci-artifacts service recovers.

Example fix

null
Defensive patterns

Strategy: retry

Validate before calling

// Optionally probe the URL before relying on it.
let resp = ureq::get(&url).call()?;
if !resp.status().is_success() {
    eprintln!("Metrics for {url} unavailable ({}); skipping parent comparison", resp.status());
}

Try / catch

match download_job_metrics(job_name, sha) {
    Ok(m) => m,
    Err(e) => {
        if e.to_string().contains("Cannot fetch metrics") {
            // Transient or missing artifact; degrade gracefully if metrics are optional
            eprintln!("warning: {e:#}");
            continue;
        }
        return Err(e);
    }
}

Prevention

When it happens

Trigger: Requesting metrics for a (job_name, sha) pair that has no stored artifact (typo in job name or SHA, or the build never published metrics); the artifacts bucket is temporarily unavailable; a network proxy returns an error status.

Common situations: Comparing against a parent commit SHA whose build failed before publishing metrics; local citool run pointed at a SHA that only exists locally and was never built by CI; transient ci-artifacts outage.

Related errors


AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10). Data as JSON: /api/errors/2d29ed47e5fac942. Report an issue: GitHub.