astrid-runtime/astrid · error
failed to fetch {name} from {url} (HTTP {})
Error message
failed to fetch {name} from {url} (HTTP {}) What it means
This error is raised by fetch_url_bytes in init_signed_source.rs when an HTTP GET for a signed-distribution resource completes but returns a non-2xx status. The library bails with the resource name, its URL, and the HTTP status so the user knows exactly which remote artifact could not be downloaded during `astrid init` with a signed source. It guards the trust chain: manifests, signatures, and capsule members must all be fetched successfully before verification can proceed.
Source
Thrown at crates/astrid-cli/src/commands/init_signed_source.rs:272
url.path_segments_mut()
.map_err(|()| anyhow::anyhow!("signed source URL cannot contain path segments"))?
.pop()
.push(file_name);
fetch_url_bytes(url.as_str(), file_name, 1024 * 1024).await
}
async fn fetch_url_bytes(url: &str, name: &str, limit: usize) -> anyhow::Result<Vec<u8>> {
let client = reqwest::Client::builder()
.user_agent("astrid-cli")
.timeout(std::time::Duration::from_secs(30))
.build()?;
let response = client
.get(url)
.send()
.await
.with_context(|| format!("failed to fetch {name}"))?;
if !response.status().is_success() {
bail!(
"failed to fetch {name} from {url} (HTTP {})",
response.status()
);
}
let mut bytes = Vec::new();
let mut response = response;
while let Some(chunk) = response.chunk().await? {
bytes.extend_from_slice(&chunk);
anyhow::ensure!(bytes.len() <= limit, "{name} exceeds size limit");
}
Ok(bytes)
}
/// Bind exact TOML bytes into the signed lock, then verify that lock.
fn verify_signed_manifest(
home: &AstridHome,
manifest: &DistroManifest,
manifest_hash: &str,View on GitHub (pinned to affd8760f4)
Solutions
- Open the URL from the error message in a browser or `curl -I` to see the actual status and fix the cause (404: correct the URL or tag; 403/401: add authentication or make the artifact public).
- Check network/proxy configuration — corporate proxies or firewalls may return 403/502 for the host; configure HTTPS_PROXY or allowlist the domain.
- Re-run the command; 429/5xx are often transient, so retry after a backoff or pin to a mirror.
- If the upstream project restructured its repo, update the capsule source URLs in Distro.toml/Distro.lock to the new location.
Example fix
// before (Distro.toml capsule source) source = "https://example.com/distros/mydistro/capsules/foo-1.0.0.capsule" // after (correct tag/path after upstream re-tag) source = "https://example.com/distros/mydistro/v1.2/capsules/foo-1.0.0.capsule"
Defensive patterns
Strategy: retry
Validate before calling
let url: Url = source.parse()?;
let head = client.head(url.clone()).send().await?;
if !head.status().is_success() {
eprintln!("artifact unreachable: {} -> {}", url, head.status());
} Type guard
fn is_ok_response(resp: &reqwest::Response) -> bool { resp.status().is_success() } Try / catch
match fetch_url_bytes(&client, &name, &url).await {
Ok(bytes) => bytes,
Err(e) if e.to_string().contains("HTTP 429") || e.to_string().contains("HTTP 5") => {
tokio::time::sleep(Duration::from_secs(5)).await;
retry_with_backoff(|| fetch_url_bytes(&client, &name, &url), 3).await?
}
Err(e) => return Err(e.context("check the URL and network/proxy settings")),
} Prevention
- curl -I every artifact URL in Distro.toml before running init against a new distro
- Pin capsule sources to immutable URLs (tags/commit hashes), not mutable branches
- Configure HTTPS_PROXY/token env vars when fetching from private hosts
- Add retries with backoff for 429/5xx statuses in your wrapper scripts
When it happens
Trigger: fetch_manifest_bytes or fetch_signed_member calls fetch_url_bytes; the reqwest client sends the GET successfully (no transport error) but response.status().is_success() is false — e.g. 404 because the URL/path in Distro.toml is wrong, 403 from a private repo, 429 rate limit, or 5xx from the host.
Common situations: Typo'd or stale capsule source URLs in Distro.toml; manifest moved to a new tag/branch so the pinned URL 404s; GitHub raw URL pointing at a private repository without a token; corporate proxy or CDN returning 403/502; temporarily down hosting service returning 500.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- {label} download failed: HTTP {status}
- {label} download failed
- no GitHub releases found for {org}/{repo}
- GitHub API rate limit exceeded - try again later
- GitHub API returned {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/4f831b116f2fced3.
Report an issue: GitHub.