davila7/claude-code-templates · error · anyhow::Error
HTTP {}
Error message
HTTP {} What it means
The GitHub contents API request inside `walk` returned a non-success, non-404 HTTP status. The code explicitly maps 404 to Ok(false) but any other status (401, 403, 429, 5xx) becomes an anyhow error showing the numeric code.
Source
Thrown at cli-rust/src/github.rs:90
Ok(Some(files))
}
fn walk(
api_url: &str,
relative_path: &str,
skill_base_name: &str,
out: &mut Vec<DownloadedFile>,
) -> Result<bool> {
let resp = client()?
.get(api_url)
.header("Accept", "application/vnd.github.v3+json")
.send()?;
if resp.status().as_u16() == 404 {
return Ok(false);
}
if !resp.status().is_success() {
return Err(anyhow!("HTTP {}", resp.status().as_u16()));
}
let contents: Value = resp.json()?;
let items = contents
.as_array()
.ok_or_else(|| anyhow!("unexpected contents API response"))?;
for item in items {
let name = item.get("name").and_then(|v| v.as_str()).unwrap_or("");
let item_type = item.get("type").and_then(|v| v.as_str()).unwrap_or("");
let item_path = if relative_path.is_empty() {
name.to_string()
} else {
format!("{relative_path}/{name}")
};
if item_type == "file" {
match item.get("download_url").and_then(|v| v.as_str()) {View on GitHub (pinned to a0851ed10c)
Solutions
- Set a GITHUB_TOKEN (or gh auth token) to raise the rate limit from 60/hr to 5000/hr
- Retry with backoff on 403/429 honoring Retry-After header
- Confirm the repo/path still exists and is public (or token has access)
- Cache directory listings to reduce contents API call volume during walk
Example fix
// before
let resp = client()?.get(url).send()?;
if resp.status().as_u16() == 404 { return Ok(false); }
// after — honor rate-limit Retry-After
let resp = client()?.get(url).send()?;
let status = resp.status().as_u16();
if status == 404 { return Ok(false); }
if status == 429 || status == 403 {
let wait = resp.headers().get("retry-after").and_then(|v| v.to_str().ok()).and_then(|s| s.parse::<u64>().ok()).unwrap_or(60);
std::thread::sleep(Duration::from_secs(wait));
// retry once...
} Defensive patterns
Strategy: retry
Validate before calling
// Check rate limit remaining before a walk burst
let remaining = client()?.get("https://api.github.com/rate_limit").send()?
.json::<Value>()?["resources"]["core"]["remaining"].as_u64().unwrap_or(0);
if remaining < 50 { /* set GITHUB_TOKEN or delay */ } Try / catch
// match on the numeric status instead of blanket-propagating
let status = resp.status().as_u16();
if status == 404 { return Ok(false); }
if status == 429 || status == 403 {
let wait = resp.headers().get("retry-after")
.and_then(|v| v.to_str().ok()).and_then(|s| s.parse::<u64>().ok()).unwrap_or(60);
std::thread::sleep(Duration::from_secs(wait));
// retry once, then give up
}
if !resp.status().is_success() { return Err(anyhow!("HTTP {status}")); } Prevention
- Always configure GITHUB_TOKEN for CI or heavy use
- Cache directory listings so repeat walks don't re-hit the contents API
- Add jittered backoff around every GitHub API call
When it happens
Trigger: Walking a skill tree via download_skill_tree when GitHub rate limits the unauthenticated API (403/429 with no token), an expired/revoked token is used (401), the repo was made private or removed mid-walk, or GitHub returns 5xx.
Common situations: CI pipelines hitting the 60 req/hr unauthenticated rate limit; missing GITHUB_TOKEN env var; repo renamed/deleted; GitHub secondary rate limiting on many rapid contents API calls.
Related errors
- GitHub API error: ${response.status}
- unexpected contents API response
- Warning: Could not fetch category ${item.name}:
- failed to launch Node CLI: {e}. Is Node.js installed?
- failed to build HTTP client: {e}
AI-assisted analysis of davila7/claude-code-templates@a0851ed10c (2026-08-28).
Data as JSON: /api/errors/3770f4989602684e.
Report an issue: GitHub.