rust-lang/rust · error · anyhow::Error
cannot deserialize metrics from {url}
Error message
cannot deserialize metrics from {url} What it means
Thrown by download_job_metrics when the HTTP response body cannot be deserialized into the expected JsonRoot structure (read_json fails). The URL is included so the caller can fetch and inspect the malformed payload. This indicates the artifact was served (status was 2xx) but its content does not match the metrics JSON schema.
Source
Thrown at src/ci/citool/src/metrics.rs:101
.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)
}
fn get_metrics_url(job_name: &str, sha: &str) -> String {
let suffix = if job_name.ends_with("-alt") { "-alt" } else { "" };
format!("https://ci-artifacts.rust-lang.org/rustc-builds{suffix}/{sha}/metrics-{job_name}.json")
}
View on GitHub (pinned to 7088e4b63a)
Solutions
- Open the URL from the error in a browser and inspect the actual content to see how it deviates from expected JSON.
- Remove .citool-cache/<sha>/ to force a fresh download and rule out local cache corruption.
- If the upstream schema changed, update the JsonRoot struct in metrics.rs to match.
- If the payload is an HTML error page, treat it as a transient upstream issue and retry.
Example fix
null
Defensive patterns
Strategy: validation
Validate before calling
// Before deserializing, sanity-check the body looks like JSON.
let body = response.body_mut().read_to_string()?;
let trimmed = body.trim_start();
if !trimmed.starts_with('{') && !trimmed.starts_with('[') {
eprintln!("Metrics payload at {url} is not JSON (got '{}'); skipping", &body[..body.len().min(80)]);
return Ok(default);
} Try / catch
let data: JsonRoot = match response.body_mut().read_json() {
Ok(d) => d,
Err(e) => {
eprintln!("warning: cannot deserialize metrics from {url}: {e}");
// fall back to empty/default metrics if acceptable for the caller
JsonRoot::default()
}
}; Prevention
- Pin citool and the publishing tool to compatible versions so JsonRoot stays in sync.
- Clear .citool-cache when switching branches to avoid stale/corrupt local files.
- Log the raw payload length when deserialization fails to spot truncation.
When it happens
Trigger: The metrics endpoint returns an HTML error page or partial JSON (truncated upload); the JSON schema changed and citool's JsonRoot struct is out of date; a cached file in .citool-cache was corrupted on disk.
Common situations: ci-artifacts served a truncated file due to an interrupted upload; version skew between the publishing tool and citool's deserialization struct; disk corruption of the local cache file.
Related errors
- Cannot fetch metrics from {url}: {} {}
- Cannot get jobs of workflow run {workflow_run_id}: {status}
- duplicate job name `{job_name}` in section `{section}`
- PR job `{}` differs from corresponding Auto job `{}` in conf
- Auto job `{job}` cannot have `continue_on_error: true`. If t
AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10).
Data as JSON: /api/errors/75a64052dc59438f.
Report an issue: GitHub.