{"record":{"id":"4f831b116f2fced3","repo":"astrid-runtime/astrid","slug":"failed-to-fetch-name-from-url-http","errorCode":null,"errorMessage":"failed to fetch {name} from {url} (HTTP {})","messagePattern":"failed to fetch (.+?) from (.+?) \\(HTTP (.+?)\\)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/init_signed_source.rs","lineNumber":272,"sourceCode":"    url.path_segments_mut()\n        .map_err(|()| anyhow::anyhow!(\"signed source URL cannot contain path segments\"))?\n        .pop()\n        .push(file_name);\n    fetch_url_bytes(url.as_str(), file_name, 1024 * 1024).await\n}\n\nasync fn fetch_url_bytes(url: &str, name: &str, limit: usize) -> anyhow::Result<Vec<u8>> {\n    let client = reqwest::Client::builder()\n        .user_agent(\"astrid-cli\")\n        .timeout(std::time::Duration::from_secs(30))\n        .build()?;\n    let response = client\n        .get(url)\n        .send()\n        .await\n        .with_context(|| format!(\"failed to fetch {name}\"))?;\n    if !response.status().is_success() {\n        bail!(\n            \"failed to fetch {name} from {url} (HTTP {})\",\n            response.status()\n        );\n    }\n    let mut bytes = Vec::new();\n    let mut response = response;\n    while let Some(chunk) = response.chunk().await? {\n        bytes.extend_from_slice(&chunk);\n        anyhow::ensure!(bytes.len() <= limit, \"{name} exceeds size limit\");\n    }\n    Ok(bytes)\n}\n\n/// Bind exact TOML bytes into the signed lock, then verify that lock.\nfn verify_signed_manifest(\n    home: &AstridHome,\n    manifest: &DistroManifest,\n    manifest_hash: &str,","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/init_signed_source.rs#L254-L290","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (Distro.toml capsule source)\nsource = \"https://example.com/distros/mydistro/capsules/foo-1.0.0.capsule\"\n// after (correct tag/path after upstream re-tag)\nsource = \"https://example.com/distros/mydistro/v1.2/capsules/foo-1.0.0.capsule\"","handlingStrategy":"retry","validationCode":"let url: Url = source.parse()?;\nlet head = client.head(url.clone()).send().await?;\nif !head.status().is_success() {\n    eprintln!(\"artifact unreachable: {} -> {}\", url, head.status());\n}","typeGuard":"fn is_ok_response(resp: &reqwest::Response) -> bool { resp.status().is_success() }","tryCatchPattern":"match fetch_url_bytes(&client, &name, &url).await {\n    Ok(bytes) => bytes,\n    Err(e) if e.to_string().contains(\"HTTP 429\") || e.to_string().contains(\"HTTP 5\") => {\n        tokio::time::sleep(Duration::from_secs(5)).await;\n        retry_with_backoff(|| fetch_url_bytes(&client, &name, &url), 3).await?\n    }\n    Err(e) => return Err(e.context(\"check the URL and network/proxy settings\")),\n}","preventionTips":["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"],"tags":["network","http","rust","download","cli"],"backgroundTag":"http-error-response","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}