astrid-runtime/astrid · warning
GitHub API rate limit exceeded - try again later
Error message
GitHub API rate limit exceeded - try again later
What it means
Raised by `fetch_github_latest_version` when GitHub responds with 429 TOO_MANY_REQUESTS or 403 FORBIDDEN, which is how GitHub signals API rate limiting. Unauthenticated GitHub API calls are limited to 60 requests/hour per IP, and `astrid capsule update` can check many capsules in one run. The message explicitly tells you to retry later.
Source
Thrown at crates/astrid-cli/src/commands/capsule/install_update.rs:51
async fn fetch_github_latest_version(
client: &reqwest::Client,
org: &str,
repo: &str,
) -> anyhow::Result<semver::Version> {
let api_url = format!("https://api.github.com/repos/{org}/{repo}/releases/latest");
let response = client
.get(&api_url)
.send()
.await
.context("failed to reach GitHub API")?;
if response.status() == reqwest::StatusCode::NOT_FOUND {
bail!("no GitHub releases found for {org}/{repo}");
}
if response.status() == reqwest::StatusCode::TOO_MANY_REQUESTS
|| response.status() == reqwest::StatusCode::FORBIDDEN
{
bail!("GitHub API rate limit exceeded - try again later");
}
if !response.status().is_success() {
bail!("GitHub API returned {}", response.status());
}
let json: serde_json::Value = response
.json()
.await
.context("failed to parse GitHub API response")?;
let tag_name = json
.get("tag_name")
.and_then(serde_json::Value::as_str)
.filter(|s| !s.is_empty())
.ok_or_else(|| anyhow::anyhow!("GitHub release has missing or empty tag_name"))?;
let version_str = strip_version_prefix(tag_name);
semver::Version::parse(version_str)
.with_context(|| format!("GitHub tag '{tag_name}' is not valid semver"))View on GitHub (pinned to affd8760f4)
Solutions
- Wait until the rate-limit window resets (check the `X-RateLimit-Reset` response header) and re-run `astrid capsule update`.
- Set GITHUB_TOKEN / provide authenticated GitHub credentials so the limit rises from 60 to 5,000 requests/hour, if your setup forwards them.
- Update only the specific capsules you need (`astrid capsule update --workspace <name>`) instead of all capsules.
- Check your network: switch off a shared VPN/runner IP or add caching in CI to avoid repeated update checks.
Example fix
// before: unauthenticated, shared-IP CI run fails astrid capsule update --workspace // error: GitHub API rate limit exceeded - try again later // after: schedule less often and export a token export GITHUB_TOKEN=ghp_... astrid capsule update --workspace
Defensive patterns
Strategy: retry
Try / catch
match check_remote_version(&client, &source, &version) {
UpdateCheck::Failed { reason } if reason.contains("rate limit exceeded") => {
tokio::time::sleep(backoff).await;
retry_with_backoff(3, backoff, || check_remote_version(&client, &source, &version)).await
},
other => handle(other),
} Prevention
- Provide an authenticated GitHub token (GITHUB_TOKEN) to raise the 60/hr anonymous limit.
- Cache the latest-version check result; do not re-check every invocation.
- Batch update checks on a schedule (e.g. daily in CI) rather than per-command.
- Target specific capsules for update instead of checking the entire fleet each time.
When it happens
Trigger: Running `astrid capsule update` in workspace mode when the machine's IP has exhausted the unauthenticated GitHub API quota (60 req/hr), e.g. CI runners sharing egress IPs, or checking many GitHub-sourced capsules in one batch. Also 403 from GitHub's abuse/rate-limit responses.
Common situations: CI pipelines on shared runners; corporate NAT with many users hitting api.github.com; bulk updates of dozens of capsules in a loop; running update repeatedly in a short window.
Related errors
- GitHub API returned {} fetching release {resolved_ref} of {o
- no GitHub releases found for {org}/{repo}
- GitHub API returned {}
- GitHub API error querying release tag {candidate} for {org}/
- GitHub API returned {} for {org}/{repo} latest release
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/f3a7b748fe26ff90.
Report an issue: GitHub.