{"record":{"id":"e01e4429596f1123","repo":"astrid-runtime/astrid","slug":"github-api-returned-fetching-release-resolved","errorCode":null,"errorMessage":"GitHub API returned {} fetching release {resolved_ref} of {org}/{repo}","messagePattern":"GitHub API returned (.+?) fetching release (.+?) of (.+?)/(.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/capsule/install.rs","lineNumber":443,"sourceCode":"\n    // Authenticated when a token is present (see `github_api_client`).\n    let client = github_api_client()?;\n\n    let resolved_ref = resolve_github_ref(&client, &org, &repo, version, tag).await?;\n\n    // Fetch the resolved release's assets and pick the right `<name>.capsule`\n    // (the same selection the install path uses), so a release shipping\n    // several capsules downloads the one the seal asked for rather than the\n    // first. A missing `.capsule` asset is a hard error — seal requires\n    // pre-built release artifacts.\n    let api_url = release_tag_url(&org, &repo, &resolved_ref)?;\n    let response = client\n        .get(&api_url)\n        .send()\n        .await\n        .context(\"failed to fetch release metadata\")?;\n    if !response.status().is_success() {\n        bail!(\n            \"GitHub API returned {} fetching release {resolved_ref} of {org}/{repo}\",\n            response.status()\n        );\n    }\n    let json: serde_json::Value = response.json().await.context(\"invalid release metadata\")?;\n    let assets = json\n        .get(\"assets\")\n        .and_then(serde_json::Value::as_array)\n        .map(Vec::as_slice)\n        .unwrap_or_default();\n    let candidates = capsule_assets(assets);\n    let names: Vec<&str> = candidates.iter().map(|(n, _)| n.as_str()).collect();\n    let Some(idx) = pick_capsule(&names, name_hint)? else {\n        bail!(\n            \"release {resolved_ref} of {org}/{repo} ships no .capsule asset — \\\n             seal requires pre-built release artifacts\"\n        );\n    };","sourceCodeStart":425,"sourceCodeEnd":461,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/capsule/install.rs#L425-L461","documentation":"`resolve_capsule_to_file` calls the GitHub releases API to look up release metadata. If the HTTP response status is not a success, it bails embedding the numeric/text status and the ref/org/repo being resolved. This is a guarded HTTP failure — the API answered, but with an error status — surfaced with context instead of letting the request proceed to JSON parsing.","triggerScenarios":"The `client.get(&api_url)` response has `!response.status().is_success()` — 404 for a nonexistent tag/release or repo, 403 for GitHub API rate limiting, 401 for private repos without a token, 5xx from GitHub.","commonSituations":"Exhausted unauthenticated GitHub API rate limit (60 req/hr) returning 403; typo in the pinned tag yielding 404; private repository without GITHUB_TOKEN; GitHub incidents returning 5xx.","solutions":["Check the status in the message: 404 means the ref/repo doesn't exist — verify the tag and org/repo spelling.","If 403/429, wait for the GitHub rate-limit window or authenticate with a GITHUB_TOKEN.","For private repos, ensure credentials are configured so API calls are authorized.","Retry later on 5xx (check https://www.githubstatus.com), or use a cached/cloned source install meanwhile."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// verify the tag exists and you are within the rate limit before resolving\n// curl -s -o /dev/null -w '%{http_code}' https://api.github.com/repos/ORG/REPO/releases/tags/TAG  # expect 200\n// curl -s https://api.github.com/rate_limit | jq .resources.core.remaining","typeGuard":null,"tryCatchPattern":"match resolve_capsule_to_file(pin).await {\n    Err(e) if e.to_string().contains(\"GitHub API returned 403\") =>\n        eprintln!(\"GitHub rate limit hit; set GITHUB_TOKEN or wait for the window to reset.\"),\n    Err(e) if e.to_string().contains(\"GitHub API returned 404\") =>\n        eprintln!(\"Release/tag or repo not found; verify the pinned ref.\"),\n    other => other.expect(\"resolve failed\"),\n}","preventionTips":["Authenticate GitHub API calls (GITHUB_TOKEN) to raise the 60 req/hr anonymous limit.","Verify the pinned tag and org/repo spelling before installing.","Cache release lookups in CI to reduce API calls.","Retry with backoff on 5xx and monitor githubstatus.com for incidents."],"tags":["github","http","api","rate-limit"],"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"}